Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativeincubator / tst_qdeclarativeincubator.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include "testtypes.h"
42
43 #include <QUrl>
44 #include <QDir>
45 #include <QDebug>
46 #include <qtest.h>
47 #include <QPointer>
48 #include <QFileInfo>
49 #include <QDeclarativeEngine>
50 #include <QDeclarativeContext>
51 #include <QDeclarativeProperty>
52 #include <QDeclarativeComponent>
53 #include <QDeclarativeIncubator>
54 #include "../../shared/util.h"
55
56 class tst_qdeclarativeincubator : public QDeclarativeDataTest
57 {
58     Q_OBJECT
59 public:
60     tst_qdeclarativeincubator() {}
61
62 private slots:
63     void initTestCase();
64
65     void incubationMode();
66     void objectDeleted();
67     void clear();
68     void noIncubationController();
69     void forceCompletion();
70     void setInitialState();
71     void clearDuringCompletion();
72     void objectDeletionAfterInit();
73     void recursiveClear();
74     void statusChanged();
75     void asynchronousIfNested();
76     void nestedComponent();
77     void chainedAsynchronousIfNested();
78     void chainedAsynchronousIfNestedOnCompleted();
79     void selfDelete();
80     void contextDelete();
81
82 private:
83     QDeclarativeIncubationController controller;
84     QDeclarativeEngine engine;
85 };
86
87 #define VERIFY_ERRORS(component, errorfile) \
88     if (!errorfile) { \
89         if (qgetenv("DEBUG") != "" && !component.errors().isEmpty()) \
90             qWarning() << "Unexpected Errors:" << component.errors(); \
91         QVERIFY(!component.isError()); \
92         QVERIFY(component.errors().isEmpty()); \
93     } else { \
94         QFile file(QDeclarativeDataTest::instance()->testFile(errorfile)); \
95         QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); \
96         QByteArray data = file.readAll(); \
97         file.close(); \
98         QList<QByteArray> expected = data.split('\n'); \
99         expected.removeAll(QByteArray("")); \
100         QList<QDeclarativeError> errors = component.errors(); \
101         QList<QByteArray> actual; \
102         for (int ii = 0; ii < errors.count(); ++ii) { \
103             const QDeclarativeError &error = errors.at(ii); \
104             QByteArray errorStr = QByteArray::number(error.line()) + ":" +  \
105                                   QByteArray::number(error.column()) + ":" + \
106                                   error.description().toUtf8(); \
107             actual << errorStr; \
108         } \
109         if (qgetenv("DEBUG") != "" && expected != actual) \
110             qWarning() << "Expected:" << expected << "Actual:" << actual;  \
111         QCOMPARE(expected, actual); \
112     }
113
114 void tst_qdeclarativeincubator::initTestCase()
115 {
116     QDeclarativeDataTest::initTestCase();
117     registerTypes();
118     engine.setIncubationController(&controller);
119 }
120
121 void tst_qdeclarativeincubator::incubationMode()
122 {
123     {
124     QDeclarativeIncubator incubator;
125     QCOMPARE(incubator.incubationMode(), QDeclarativeIncubator::Asynchronous);
126     }
127     {
128     QDeclarativeIncubator incubator(QDeclarativeIncubator::Asynchronous);
129     QCOMPARE(incubator.incubationMode(), QDeclarativeIncubator::Asynchronous);
130     }
131     {
132     QDeclarativeIncubator incubator(QDeclarativeIncubator::Synchronous);
133     QCOMPARE(incubator.incubationMode(), QDeclarativeIncubator::Synchronous);
134     }
135     {
136     QDeclarativeIncubator incubator(QDeclarativeIncubator::AsynchronousIfNested);
137     QCOMPARE(incubator.incubationMode(), QDeclarativeIncubator::AsynchronousIfNested);
138     }
139 }
140
141 void tst_qdeclarativeincubator::objectDeleted()
142 {
143     SelfRegisteringType::clearMe();
144
145     QDeclarativeComponent component(&engine, testFileUrl("objectDeleted.qml"));
146     QVERIFY(component.isReady());
147
148     QDeclarativeIncubator incubator;
149     component.create(incubator);
150
151     QCOMPARE(incubator.status(), QDeclarativeIncubator::Loading);
152     QVERIFY(SelfRegisteringType::me() == 0);
153
154     while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
155         bool b = false;
156         controller.incubateWhile(&b);
157     }
158
159     QVERIFY(SelfRegisteringType::me() != 0);
160     QVERIFY(incubator.isLoading());
161
162     delete SelfRegisteringType::me();
163
164     {
165     bool b = true;
166     controller.incubateWhile(&b);
167     }
168
169     QVERIFY(incubator.isError());
170     VERIFY_ERRORS(incubator, "objectDeleted.errors.txt");
171     QVERIFY(incubator.object() == 0);
172 }
173
174 void tst_qdeclarativeincubator::clear()
175 {
176     SelfRegisteringType::clearMe();
177
178     QDeclarativeComponent component(&engine, testFileUrl("clear.qml"));
179     QVERIFY(component.isReady());
180
181     // Clear in null state
182     {
183     QDeclarativeIncubator incubator;
184     QVERIFY(incubator.isNull());
185     incubator.clear(); // no effect
186     QVERIFY(incubator.isNull());
187     }
188
189     // Clear in loading state
190     {
191     QDeclarativeIncubator incubator;
192     component.create(incubator);
193     QVERIFY(incubator.isLoading());
194     incubator.clear();
195     QVERIFY(incubator.isNull());
196     }
197
198     // Clear mid load
199     {
200     QDeclarativeIncubator incubator;
201     component.create(incubator);
202
203     while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
204         bool b = false;
205         controller.incubateWhile(&b);
206     }
207
208     QVERIFY(incubator.isLoading());
209     QVERIFY(SelfRegisteringType::me() != 0);
210     QPointer<SelfRegisteringType> srt = SelfRegisteringType::me();
211
212     incubator.clear();
213     QVERIFY(incubator.isNull());
214     QVERIFY(srt.isNull());
215     }
216
217     // Clear in ready state
218     {
219     QDeclarativeIncubator incubator;
220     component.create(incubator);
221
222     {
223         bool b = true;
224         controller.incubateWhile(&b);
225     }
226
227     QVERIFY(incubator.isReady());
228     QVERIFY(incubator.object() != 0);
229     QPointer<QObject> obj = incubator.object();
230
231     incubator.clear();
232     QVERIFY(incubator.isNull());
233     QVERIFY(incubator.object() == 0);
234     QVERIFY(!obj.isNull());
235
236     delete obj;
237     QVERIFY(obj.isNull());
238     }
239 }
240
241 void tst_qdeclarativeincubator::noIncubationController()
242 {
243     // All incubators should behave synchronously when there is no controller
244
245     QDeclarativeEngine engine;
246     QDeclarativeComponent component(&engine, testFileUrl("noIncubationController.qml"));
247
248     QVERIFY(component.isReady());
249
250     {
251     QDeclarativeIncubator incubator(QDeclarativeIncubator::Asynchronous);
252     component.create(incubator);
253     QVERIFY(incubator.isReady());
254     QVERIFY(incubator.object());
255     QCOMPARE(incubator.object()->property("testValue").toInt(), 1913);
256     delete incubator.object();
257     }
258
259     {
260     QDeclarativeIncubator incubator(QDeclarativeIncubator::AsynchronousIfNested);
261     component.create(incubator);
262     QVERIFY(incubator.isReady());
263     QVERIFY(incubator.object());
264     QCOMPARE(incubator.object()->property("testValue").toInt(), 1913);
265     delete incubator.object();
266     }
267
268     {
269     QDeclarativeIncubator incubator(QDeclarativeIncubator::Synchronous);
270     component.create(incubator);
271     QVERIFY(incubator.isReady());
272     QVERIFY(incubator.object());
273     QCOMPARE(incubator.object()->property("testValue").toInt(), 1913);
274     delete incubator.object();
275     }
276 }
277
278 void tst_qdeclarativeincubator::forceCompletion()
279 {
280     QDeclarativeComponent component(&engine, testFileUrl("forceCompletion.qml"));
281     QVERIFY(component.isReady());
282
283     {
284     // forceCompletion on a null incubator does nothing
285     QDeclarativeIncubator incubator;
286     QVERIFY(incubator.isNull());
287     incubator.forceCompletion();
288     QVERIFY(incubator.isNull());
289     }
290
291     {
292     // forceCompletion immediately after creating an asynchronous object completes it
293     QDeclarativeIncubator incubator;
294     QVERIFY(incubator.isNull());
295     component.create(incubator);
296     QVERIFY(incubator.isLoading());
297
298     incubator.forceCompletion();
299
300     QVERIFY(incubator.isReady());
301     QVERIFY(incubator.object() != 0);
302     QCOMPARE(incubator.object()->property("testValue").toInt(), 3499);
303
304     delete incubator.object();
305     }
306
307     {
308     // forceCompletion during creation completes it
309     SelfRegisteringType::clearMe();
310
311     QDeclarativeIncubator incubator;
312     QVERIFY(incubator.isNull());
313     component.create(incubator);
314     QVERIFY(incubator.isLoading());
315
316     while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
317         bool b = false;
318         controller.incubateWhile(&b);
319     }
320
321     QVERIFY(SelfRegisteringType::me() != 0);
322     QVERIFY(incubator.isLoading());
323
324     incubator.forceCompletion();
325
326     QVERIFY(incubator.isReady());
327     QVERIFY(incubator.object() != 0);
328     QCOMPARE(incubator.object()->property("testValue").toInt(), 3499);
329
330     delete incubator.object();
331     }
332
333     {
334     // forceCompletion on a ready incubator has no effect
335     QDeclarativeIncubator incubator;
336     QVERIFY(incubator.isNull());
337     component.create(incubator);
338     QVERIFY(incubator.isLoading());
339
340     incubator.forceCompletion();
341
342     QVERIFY(incubator.isReady());
343     QVERIFY(incubator.object() != 0);
344     QCOMPARE(incubator.object()->property("testValue").toInt(), 3499);
345
346     incubator.forceCompletion();
347
348     QVERIFY(incubator.isReady());
349     QVERIFY(incubator.object() != 0);
350     QCOMPARE(incubator.object()->property("testValue").toInt(), 3499);
351
352     delete incubator.object();
353     }
354 }
355
356 void tst_qdeclarativeincubator::setInitialState()
357 {
358     QDeclarativeComponent component(&engine, testFileUrl("setInitialState.qml"));
359     QVERIFY(component.isReady());
360
361     struct MyIncubator : public QDeclarativeIncubator
362     {
363         MyIncubator(QDeclarativeIncubator::IncubationMode mode)
364         : QDeclarativeIncubator(mode) {}
365
366         virtual void setInitialState(QObject *o) {
367             QDeclarativeProperty::write(o, "test2", 19);
368             QDeclarativeProperty::write(o, "testData1", 201);
369         }
370     };
371
372     {
373     MyIncubator incubator(QDeclarativeIncubator::Asynchronous);
374     component.create(incubator);
375     QVERIFY(incubator.isLoading());
376     bool b = true;
377     controller.incubateWhile(&b);
378     QVERIFY(incubator.isReady());
379     QVERIFY(incubator.object());
380     QCOMPARE(incubator.object()->property("myValueFunctionCalled").toBool(), false);
381     QCOMPARE(incubator.object()->property("test1").toInt(), 502);
382     QCOMPARE(incubator.object()->property("test2").toInt(), 19);
383     delete incubator.object();
384     }
385
386     {
387     MyIncubator incubator(QDeclarativeIncubator::Synchronous);
388     component.create(incubator);
389     QVERIFY(incubator.isReady());
390     QVERIFY(incubator.object());
391     QCOMPARE(incubator.object()->property("myValueFunctionCalled").toBool(), false);
392     QCOMPARE(incubator.object()->property("test1").toInt(), 502);
393     QCOMPARE(incubator.object()->property("test2").toInt(), 19);
394     delete incubator.object();
395     }
396 }
397
398 void tst_qdeclarativeincubator::clearDuringCompletion()
399 {
400     CompletionRegisteringType::clearMe();
401     SelfRegisteringType::clearMe();
402
403     QDeclarativeComponent component(&engine, testFileUrl("clearDuringCompletion.qml"));
404     QVERIFY(component.isReady());
405
406     QDeclarativeIncubator incubator;
407     component.create(incubator);
408
409     QCOMPARE(incubator.status(), QDeclarativeIncubator::Loading);
410     QVERIFY(CompletionRegisteringType::me() == 0);
411
412     while (CompletionRegisteringType::me() == 0 && incubator.isLoading()) {
413         bool b = false;
414         controller.incubateWhile(&b);
415     }
416
417     QVERIFY(CompletionRegisteringType::me() != 0);
418     QVERIFY(SelfRegisteringType::me() != 0);
419     QVERIFY(incubator.isLoading());
420
421     QPointer<QObject> srt = SelfRegisteringType::me();
422
423     incubator.clear();
424     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
425     QCoreApplication::processEvents();
426     QVERIFY(incubator.isNull());
427     QVERIFY(srt.isNull());
428 }
429
430 void tst_qdeclarativeincubator::objectDeletionAfterInit()
431 {
432     QDeclarativeComponent component(&engine, testFileUrl("clear.qml"));
433     QVERIFY(component.isReady());
434
435     struct MyIncubator : public QDeclarativeIncubator
436     {
437         MyIncubator(QDeclarativeIncubator::IncubationMode mode)
438         : QDeclarativeIncubator(mode), obj(0) {}
439
440         virtual void setInitialState(QObject *o) {
441             obj = o;
442         }
443
444         QObject *obj;
445     };
446
447     SelfRegisteringType::clearMe();
448     MyIncubator incubator(QDeclarativeIncubator::Asynchronous);
449     component.create(incubator);
450
451     while (!incubator.obj && incubator.isLoading()) {
452         bool b = false;
453         controller.incubateWhile(&b);
454     }
455
456     QVERIFY(incubator.isLoading());
457     QVERIFY(SelfRegisteringType::me() != 0);
458
459     delete incubator.obj;
460
461     incubator.clear();
462     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
463     QCoreApplication::processEvents();
464     QVERIFY(incubator.isNull());
465 }
466
467 class Switcher : public QObject
468 {
469     Q_OBJECT
470 public:
471     Switcher(QDeclarativeEngine *e) : QObject(), engine(e) { }
472
473     struct MyIncubator : public QDeclarativeIncubator
474     {
475         MyIncubator(QDeclarativeIncubator::IncubationMode mode, QObject *s)
476         : QDeclarativeIncubator(mode), switcher(s) {}
477
478         virtual void setInitialState(QObject *o) {
479             if (o->objectName() == "switchMe")
480                 connect(o, SIGNAL(switchMe()), switcher, SLOT(switchIt()));
481         }
482
483         QObject *switcher;
484     };
485
486     void start()
487     {
488         incubator = new MyIncubator(QDeclarativeIncubator::Synchronous, this);
489         component = new QDeclarativeComponent(engine, QDeclarativeDataTest::instance()->testFileUrl("recursiveClear.1.qml"));
490         component->create(*incubator);
491     }
492
493     QDeclarativeEngine *engine;
494     MyIncubator *incubator;
495     QDeclarativeComponent *component;
496
497 public slots:
498     void switchIt() {
499         component->deleteLater();
500         incubator->clear();
501         component = new QDeclarativeComponent(engine, QDeclarativeDataTest::instance()->testFileUrl("recursiveClear.2.qml"));
502         component->create(*incubator);
503     }
504 };
505
506 void tst_qdeclarativeincubator::recursiveClear()
507 {
508     Switcher switcher(&engine);
509     switcher.start();
510 }
511
512 void tst_qdeclarativeincubator::statusChanged()
513 {
514     class MyIncubator : public QDeclarativeIncubator
515     {
516     public:
517         MyIncubator(QDeclarativeIncubator::IncubationMode mode = QDeclarativeIncubator::Asynchronous)
518         : QDeclarativeIncubator(mode) {}
519
520         QList<int> statuses;
521     protected:
522         virtual void statusChanged(Status s) { statuses << s; }
523         virtual void setInitialState(QObject *) { statuses << -1; }
524     };
525
526     {
527     QDeclarativeComponent component(&engine, testFileUrl("statusChanged.qml"));
528     QVERIFY(component.isReady());
529
530     MyIncubator incubator(QDeclarativeIncubator::Synchronous);
531     component.create(incubator);
532     QVERIFY(incubator.isReady());
533     QCOMPARE(incubator.statuses.count(), 3);
534     QCOMPARE(incubator.statuses.at(0), int(QDeclarativeIncubator::Loading));
535     QCOMPARE(incubator.statuses.at(1), -1);
536     QCOMPARE(incubator.statuses.at(2), int(QDeclarativeIncubator::Ready));
537     delete incubator.object();
538     }
539
540     {
541     QDeclarativeComponent component(&engine, testFileUrl("statusChanged.qml"));
542     QVERIFY(component.isReady());
543
544     MyIncubator incubator(QDeclarativeIncubator::Asynchronous);
545     component.create(incubator);
546     QVERIFY(incubator.isLoading());
547     QCOMPARE(incubator.statuses.count(), 1);
548     QCOMPARE(incubator.statuses.at(0), int(QDeclarativeIncubator::Loading));
549
550     {
551     bool b = true;
552     controller.incubateWhile(&b);
553     }
554
555     QCOMPARE(incubator.statuses.count(), 3);
556     QCOMPARE(incubator.statuses.at(0), int(QDeclarativeIncubator::Loading));
557     QCOMPARE(incubator.statuses.at(1), -1);
558     QCOMPARE(incubator.statuses.at(2), int(QDeclarativeIncubator::Ready));
559     delete incubator.object();
560     }
561
562     {
563     QDeclarativeComponent component2(&engine, testFileUrl("statusChanged.nested.qml"));
564     QVERIFY(component2.isReady());
565
566     MyIncubator incubator(QDeclarativeIncubator::Asynchronous);
567     component2.create(incubator);
568     QVERIFY(incubator.isLoading());
569     QCOMPARE(incubator.statuses.count(), 1);
570     QCOMPARE(incubator.statuses.at(0), int(QDeclarativeIncubator::Loading));
571
572     {
573     bool b = true;
574     controller.incubateWhile(&b);
575     }
576
577     QVERIFY(incubator.isReady());
578     QCOMPARE(incubator.statuses.count(), 3);
579     QCOMPARE(incubator.statuses.at(0), int(QDeclarativeIncubator::Loading));
580     QCOMPARE(incubator.statuses.at(1), -1);
581     QCOMPARE(incubator.statuses.at(2), int(QDeclarativeIncubator::Ready));
582     delete incubator.object();
583     }
584 }
585
586 void tst_qdeclarativeincubator::asynchronousIfNested()
587 {
588     // Asynchronous if nested within a finalized context behaves synchronously
589     {
590     QDeclarativeComponent component(&engine, testFileUrl("asynchronousIfNested.1.qml"));
591     QVERIFY(component.isReady());
592
593     QObject *object = component.create();
594     QVERIFY(object != 0);
595     QCOMPARE(object->property("a").toInt(), 10);
596
597     QDeclarativeIncubator incubator(QDeclarativeIncubator::AsynchronousIfNested);
598     component.create(incubator, 0, qmlContext(object));
599
600     QVERIFY(incubator.isReady());
601     QVERIFY(incubator.object());
602     QCOMPARE(incubator.object()->property("a").toInt(), 10);
603     delete incubator.object();
604     delete object;
605     }
606
607     // Asynchronous if nested within an executing context behaves asynchronously, but prevents
608     // the parent from finishing
609     {
610     SelfRegisteringType::clearMe();
611
612     QDeclarativeComponent component(&engine, testFileUrl("asynchronousIfNested.2.qml"));
613     QVERIFY(component.isReady());
614
615     QDeclarativeIncubator incubator;
616     component.create(incubator);
617
618     QVERIFY(incubator.isLoading());
619     QVERIFY(SelfRegisteringType::me() == 0);
620     while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
621         bool b = false;
622         controller.incubateWhile(&b);
623     }
624
625     QVERIFY(SelfRegisteringType::me() != 0);
626     QVERIFY(incubator.isLoading());
627
628     QDeclarativeIncubator nested(QDeclarativeIncubator::AsynchronousIfNested);
629     component.create(nested, 0, qmlContext(SelfRegisteringType::me()));
630     QVERIFY(nested.isLoading());
631
632     while (nested.isLoading()) {
633         QVERIFY(incubator.isLoading());
634         bool b = false;
635         controller.incubateWhile(&b);
636     }
637
638     QVERIFY(nested.isReady());
639     QVERIFY(incubator.isLoading());
640
641     {
642         bool b = true;
643         controller.incubateWhile(&b);
644     }
645
646     QVERIFY(nested.isReady());
647     QVERIFY(incubator.isReady());
648
649     delete nested.object();
650     delete incubator.object();
651     }
652
653     // AsynchronousIfNested within a synchronous AsynchronousIfNested behaves synchronously
654     {
655     SelfRegisteringType::clearMe();
656
657     QDeclarativeComponent component(&engine, testFileUrl("asynchronousIfNested.3.qml"));
658     QVERIFY(component.isReady());
659
660     struct CallbackData {
661         CallbackData(QDeclarativeEngine *e) : engine(e), pass(false) {}
662         QDeclarativeEngine *engine;
663         bool pass;
664         static void callback(CallbackRegisteringType *o, void *data) {
665             CallbackData *d = (CallbackData *)data;
666
667             QDeclarativeComponent c(d->engine, QDeclarativeDataTest::instance()->testFileUrl("asynchronousIfNested.1.qml"));
668             if (!c.isReady()) return;
669
670             QDeclarativeIncubator incubator(QDeclarativeIncubator::AsynchronousIfNested);
671             c.create(incubator, 0, qmlContext(o));
672
673             if (!incubator.isReady()) return;
674
675             if (incubator.object()->property("a").toInt() != 10) return;
676
677             d->pass = true;
678         }
679     };
680
681     CallbackData cd(&engine);
682     CallbackRegisteringType::registerCallback(&CallbackData::callback, &cd);
683
684     QDeclarativeIncubator incubator(QDeclarativeIncubator::AsynchronousIfNested);
685     component.create(incubator);
686
687     QVERIFY(incubator.isReady());
688     QCOMPARE(cd.pass, true);
689
690     delete incubator.object();
691     }
692 }
693
694 void tst_qdeclarativeincubator::nestedComponent()
695 {
696     QDeclarativeComponent component(&engine, testFileUrl("nestedComponent.qml"));
697     QVERIFY(component.isReady());
698
699     QObject *object = component.create();
700
701     QDeclarativeComponent *nested = object->property("c").value<QDeclarativeComponent*>();
702     QVERIFY(nested);
703     QVERIFY(nested->isReady());
704
705     // Test without incubator
706     {
707     QObject *nestedObject = nested->create();
708     QCOMPARE(nestedObject->property("value").toInt(), 19988);
709     delete nestedObject;
710     }
711
712     // Test with incubator
713     {
714     QDeclarativeIncubator incubator(QDeclarativeIncubator::Synchronous);
715     nested->create(incubator);
716     QVERIFY(incubator.isReady());
717     QVERIFY(incubator.object());
718     QCOMPARE(incubator.object()->property("value").toInt(), 19988);
719     delete incubator.object();
720     }
721
722     delete object;
723 }
724
725 // Checks that a new AsynchronousIfNested incubator can be correctly started in the
726 // statusChanged() callback of another.
727 void tst_qdeclarativeincubator::chainedAsynchronousIfNested()
728 {
729     SelfRegisteringType::clearMe();
730
731     QDeclarativeComponent component(&engine, testFileUrl("chainedAsynchronousIfNested.qml"));
732     QVERIFY(component.isReady());
733
734     QDeclarativeIncubator incubator(QDeclarativeIncubator::Asynchronous);
735     component.create(incubator);
736
737     QVERIFY(incubator.isLoading());
738     QVERIFY(SelfRegisteringType::me() == 0);
739
740     while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
741         bool b = false;
742         controller.incubateWhile(&b);
743     }
744
745     QVERIFY(SelfRegisteringType::me() != 0);
746     QVERIFY(incubator.isLoading());
747
748     struct MyIncubator : public QDeclarativeIncubator {
749         MyIncubator(MyIncubator *next, QDeclarativeComponent *component, QDeclarativeContext *ctxt)
750         : QDeclarativeIncubator(AsynchronousIfNested), next(next), component(component), ctxt(ctxt) {}
751
752     protected:
753         virtual void statusChanged(Status s) {
754             if (s == Ready && next)
755                 component->create(*next, 0, ctxt);
756         }
757
758     private:
759         MyIncubator *next;
760         QDeclarativeComponent *component;
761         QDeclarativeContext *ctxt;
762     };
763
764     MyIncubator incubator2(0, &component, 0);
765     MyIncubator incubator1(&incubator2, &component, qmlContext(SelfRegisteringType::me()));
766
767     component.create(incubator1, 0, qmlContext(SelfRegisteringType::me()));
768
769     QVERIFY(incubator.isLoading());
770     QVERIFY(incubator1.isLoading());
771     QVERIFY(incubator2.isNull());
772
773     while (incubator1.isLoading()) {
774         QVERIFY(incubator.isLoading());
775         QVERIFY(incubator1.isLoading());
776         QVERIFY(incubator2.isNull());
777
778         bool b = false;
779         controller.incubateWhile(&b);
780     }
781
782     QVERIFY(incubator.isLoading());
783     QVERIFY(incubator1.isReady());
784     QVERIFY(incubator2.isLoading());
785
786     while (incubator2.isLoading()) {
787         QVERIFY(incubator.isLoading());
788         QVERIFY(incubator1.isReady());
789         QVERIFY(incubator2.isLoading());
790
791         bool b = false;
792         controller.incubateWhile(&b);
793     }
794
795     QVERIFY(incubator.isLoading());
796     QVERIFY(incubator1.isReady());
797     QVERIFY(incubator2.isReady());
798
799     {
800     bool b = true;
801     controller.incubateWhile(&b);
802     }
803
804     QVERIFY(incubator.isReady());
805     QVERIFY(incubator1.isReady());
806     QVERIFY(incubator2.isReady());
807 }
808
809 // Checks that new AsynchronousIfNested incubators can be correctly chained if started in
810 // componentCompleted().
811 void tst_qdeclarativeincubator::chainedAsynchronousIfNestedOnCompleted()
812 {
813     SelfRegisteringType::clearMe();
814
815     QDeclarativeComponent component(&engine, testFileUrl("chainInCompletion.qml"));
816     QVERIFY(component.isReady());
817
818     QDeclarativeComponent c1(&engine, testFileUrl("chainedAsynchronousIfNested.qml"));
819     QVERIFY(c1.isReady());
820
821     struct MyIncubator : public QDeclarativeIncubator {
822         MyIncubator(MyIncubator *next, QDeclarativeComponent *component, QDeclarativeContext *ctxt)
823         : QDeclarativeIncubator(AsynchronousIfNested), next(next), component(component), ctxt(ctxt) {}
824
825     protected:
826         virtual void statusChanged(Status s) {
827             if (s == Ready && next) {
828                 component->create(*next, 0, ctxt);
829             }
830         }
831
832     private:
833         MyIncubator *next;
834         QDeclarativeComponent *component;
835         QDeclarativeContext *ctxt;
836     };
837
838     struct CallbackData {
839         CallbackData(QDeclarativeComponent *c, MyIncubator *i, QDeclarativeContext *ct)
840             : component(c), incubator(i), ctxt(ct) {}
841         QDeclarativeComponent *component;
842         MyIncubator *incubator;
843         QDeclarativeContext *ctxt;
844         static void callback(CompletionCallbackType *, void *data) {
845             CallbackData *d = (CallbackData *)data;
846             d->component->create(*d->incubator, 0, d->ctxt);
847         }
848     };
849
850     QDeclarativeIncubator incubator(QDeclarativeIncubator::Asynchronous);
851     component.create(incubator);
852
853     QVERIFY(incubator.isLoading());
854     QVERIFY(SelfRegisteringType::me() == 0);
855
856     while (SelfRegisteringType::me() == 0 && incubator.isLoading()) {
857         bool b = false;
858         controller.incubateWhile(&b);
859     }
860
861     QVERIFY(SelfRegisteringType::me() != 0);
862     QVERIFY(incubator.isLoading());
863
864     MyIncubator incubator3(0, &c1, qmlContext(SelfRegisteringType::me()));
865     MyIncubator incubator2(&incubator3, &c1, qmlContext(SelfRegisteringType::me()));
866     MyIncubator incubator1(&incubator2, &c1, qmlContext(SelfRegisteringType::me()));
867
868     // start incubator1 in componentComplete
869     CallbackData cd(&c1, &incubator1, qmlContext(SelfRegisteringType::me()));
870     CompletionCallbackType::registerCallback(&CallbackData::callback, &cd);
871
872     while (!incubator1.isLoading()) {
873         QVERIFY(incubator.isLoading());
874         QVERIFY(incubator2.isNull());
875         QVERIFY(incubator3.isNull());
876
877         bool b = false;
878         controller.incubateWhile(&b);
879     }
880
881     QVERIFY(incubator.isLoading());
882     QVERIFY(incubator1.isLoading());
883     QVERIFY(incubator2.isNull());
884     QVERIFY(incubator3.isNull());
885
886     while (incubator1.isLoading()) {
887         QVERIFY(incubator.isLoading());
888         QVERIFY(incubator1.isLoading());
889         QVERIFY(incubator2.isNull());
890         QVERIFY(incubator3.isNull());
891
892         bool b = false;
893         controller.incubateWhile(&b);
894     }
895
896     QVERIFY(incubator.isLoading());
897     QVERIFY(incubator1.isReady());
898     QVERIFY(incubator2.isLoading());
899     QVERIFY(incubator3.isNull());
900
901     while (incubator2.isLoading()) {
902         QVERIFY(incubator.isLoading());
903         QVERIFY(incubator1.isReady());
904         QVERIFY(incubator2.isLoading());
905         QVERIFY(incubator3.isNull());
906
907         bool b = false;
908         controller.incubateWhile(&b);
909     }
910
911     QVERIFY(incubator.isLoading());
912     QVERIFY(incubator1.isReady());
913     QVERIFY(incubator2.isReady());
914     QVERIFY(incubator3.isLoading());
915
916     while (incubator3.isLoading()) {
917         QVERIFY(incubator.isLoading());
918         QVERIFY(incubator1.isReady());
919         QVERIFY(incubator2.isReady());
920         QVERIFY(incubator3.isLoading());
921
922         bool b = false;
923         controller.incubateWhile(&b);
924     }
925
926     {
927     bool b = true;
928     controller.incubateWhile(&b);
929     }
930
931     QVERIFY(incubator.isReady());
932     QVERIFY(incubator1.isReady());
933     QVERIFY(incubator2.isReady());
934     QVERIFY(incubator3.isReady());
935 }
936
937 void tst_qdeclarativeincubator::selfDelete()
938 {
939     struct MyIncubator : public QDeclarativeIncubator {
940         MyIncubator(bool *done, Status status, IncubationMode mode)
941         : QDeclarativeIncubator(mode), done(done), status(status) {}
942
943     protected:
944         virtual void statusChanged(Status s) {
945             if (s == status) {
946                 *done = true;
947                 if (s == Ready) delete object();
948                 delete this;
949             }
950         }
951
952     private:
953         bool *done;
954         Status status;
955     };
956
957     {
958     QDeclarativeComponent component(&engine, testFileUrl("selfDelete.qml"));
959
960 #define DELETE_TEST(status, mode) { \
961     bool done = false; \
962     component.create(*(new MyIncubator(&done, status, mode))); \
963     bool True = true; \
964     controller.incubateWhile(&True); \
965     QVERIFY(done == true); \
966     }
967
968     DELETE_TEST(QDeclarativeIncubator::Loading, QDeclarativeIncubator::Synchronous);
969     DELETE_TEST(QDeclarativeIncubator::Ready, QDeclarativeIncubator::Synchronous);
970     DELETE_TEST(QDeclarativeIncubator::Loading, QDeclarativeIncubator::Asynchronous);
971     DELETE_TEST(QDeclarativeIncubator::Ready, QDeclarativeIncubator::Asynchronous);
972
973 #undef DELETE_TEST
974     }
975
976     // Delete within error status
977     {
978     SelfRegisteringType::clearMe();
979
980     QDeclarativeComponent component(&engine, testFileUrl("objectDeleted.qml"));
981     QVERIFY(component.isReady());
982
983     bool done = false;
984     MyIncubator *incubator = new MyIncubator(&done, QDeclarativeIncubator::Error,
985                                              QDeclarativeIncubator::Asynchronous);
986     component.create(*incubator);
987
988     QCOMPARE(incubator->QDeclarativeIncubator::status(), QDeclarativeIncubator::Loading);
989     QVERIFY(SelfRegisteringType::me() == 0);
990
991     while (SelfRegisteringType::me() == 0 && incubator->isLoading()) {
992         bool b = false;
993         controller.incubateWhile(&b);
994     }
995
996     QVERIFY(SelfRegisteringType::me() != 0);
997     QVERIFY(incubator->isLoading());
998
999     delete SelfRegisteringType::me();
1000
1001     {
1002     bool b = true;
1003     controller.incubateWhile(&b);
1004     }
1005
1006     QVERIFY(done);
1007     }
1008 }
1009
1010 // Test that QML doesn't crash if the context is deleted prior to the incubator
1011 // first executing.
1012 void tst_qdeclarativeincubator::contextDelete()
1013 {
1014     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
1015     QDeclarativeComponent component(&engine, testFileUrl("contextDelete.qml"));
1016
1017     QDeclarativeIncubator incubator;
1018     component.create(incubator, context);
1019
1020     delete context;
1021
1022     {
1023         bool b = false;
1024         controller.incubateWhile(&b);
1025     }
1026 }
1027
1028 QTEST_MAIN(tst_qdeclarativeincubator)
1029
1030 #include "tst_qdeclarativeincubator.moc"