Rename QDeclarative symbols to QQuick and QQml
[profile/ivi/qtdeclarative.git] / tests / auto / quick / qquickloader / tst_qquickloader.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 <qtest.h>
42
43 #include <QSignalSpy>
44
45 #include <QtQml/qqmlengine.h>
46 #include <QtQml/qqmlcomponent.h>
47 #include <QtQml/qqmlincubator.h>
48 #include <private/qquickloader_p.h>
49 #include "testhttpserver.h"
50 #include "../../shared/util.h"
51
52 #define SERVER_PORT 14450
53
54 class PeriodicIncubationController : public QObject,
55     public QQmlIncubationController
56 {
57 public:
58     PeriodicIncubationController() {
59         startTimer(16);
60     }
61
62 protected:
63     virtual void timerEvent(QTimerEvent *) {
64         incubateFor(15);
65     }
66 };
67
68 class tst_QQuickLoader : public QQmlDataTest
69
70 {
71     Q_OBJECT
72 public:
73     tst_QQuickLoader();
74
75 private slots:
76     void sourceOrComponent();
77     void sourceOrComponent_data();
78     void clear();
79     void urlToComponent();
80     void componentToUrl();
81     void anchoredLoader();
82     void sizeLoaderToItem();
83     void sizeItemToLoader();
84     void noResize();
85     void networkRequestUrl();
86     void failNetworkRequest();
87 //    void networkComponent();
88     void active();
89     void initialPropertyValues_data();
90     void initialPropertyValues();
91     void initialPropertyValuesBinding();
92     void initialPropertyValuesError_data();
93     void initialPropertyValuesError();
94
95     void deleteComponentCrash();
96     void nonItem();
97     void vmeErrors();
98     void creationContext();
99     void QTBUG_16928();
100     void implicitSize();
101     void QTBUG_17114();
102     void asynchronous_data();
103     void asynchronous();
104     void asynchronous_clear();
105
106     void parented();
107     void sizeBound();
108
109 private:
110     QQmlEngine engine;
111 };
112
113
114 tst_QQuickLoader::tst_QQuickLoader()
115 {
116 }
117
118 void tst_QQuickLoader::sourceOrComponent()
119 {
120     QFETCH(QString, sourceOrComponent);
121     QFETCH(QString, sourceDefinition);
122     QFETCH(QUrl, sourceUrl);
123     QFETCH(QString, errorString);
124
125     bool error = !errorString.isEmpty();
126     if (error)
127         QTest::ignoreMessage(QtWarningMsg, errorString.toUtf8().constData());
128
129     QQmlComponent component(&engine);
130     component.setData(QByteArray(
131             "import QtQuick 2.0\n"
132             "Loader {\n"
133             "   property int onItemChangedCount: 0\n"
134             "   property int onSourceChangedCount: 0\n"
135             "   property int onSourceComponentChangedCount: 0\n"
136             "   property int onStatusChangedCount: 0\n"
137             "   property int onProgressChangedCount: 0\n"
138             "   property int onLoadedCount: 0\n")
139             + sourceDefinition.toUtf8()
140             + QByteArray(
141             "   onItemChanged: onItemChangedCount += 1\n"
142             "   onSourceChanged: onSourceChangedCount += 1\n"
143             "   onSourceComponentChanged: onSourceComponentChangedCount += 1\n"
144             "   onStatusChanged: onStatusChangedCount += 1\n"
145             "   onProgressChanged: onProgressChangedCount += 1\n"
146             "   onLoaded: onLoadedCount += 1\n"
147             "}")
148         , dataDirectoryUrl());
149
150     QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
151     QVERIFY(loader != 0);
152     QCOMPARE(loader->item() == 0, error);
153     QCOMPARE(loader->source(), sourceUrl);
154     QCOMPARE(loader->progress(), 1.0);
155
156     QCOMPARE(loader->status(), error ? QQuickLoader::Error : QQuickLoader::Ready);
157     QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), error ? 0: 1);
158
159     if (!error) {
160         bool sourceComponentIsChildOfLoader = false;
161         for (int ii = 0; ii < loader->children().size(); ++ii) {
162             QQmlComponent *c = qobject_cast<QQmlComponent*>(loader->children().at(ii));
163             if (c && c == loader->sourceComponent()) {
164                 sourceComponentIsChildOfLoader = true;
165             }
166         }
167         QVERIFY(sourceComponentIsChildOfLoader);
168     }
169
170     if (sourceOrComponent == "component") {
171         QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 1);
172         QCOMPARE(loader->property("onSourceChangedCount").toInt(), 0);
173     } else {
174         QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 0);
175         QCOMPARE(loader->property("onSourceChangedCount").toInt(), 1);
176     }
177     QCOMPARE(loader->property("onStatusChangedCount").toInt(), 1);
178     QCOMPARE(loader->property("onProgressChangedCount").toInt(), 1);
179
180     QCOMPARE(loader->property("onItemChangedCount").toInt(), error ? 0 : 1);
181     QCOMPARE(loader->property("onLoadedCount").toInt(), error ? 0 : 1);
182
183     delete loader;
184 }
185
186 void tst_QQuickLoader::sourceOrComponent_data()
187 {
188     QTest::addColumn<QString>("sourceOrComponent");
189     QTest::addColumn<QString>("sourceDefinition");
190     QTest::addColumn<QUrl>("sourceUrl");
191     QTest::addColumn<QString>("errorString");
192
193     QTest::newRow("source") << "source" << "source: 'Rect120x60.qml'\n" << testFileUrl("Rect120x60.qml") << "";
194     QTest::newRow("sourceComponent") << "component" << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
195     QTest::newRow("invalid source") << "source" << "source: 'IDontExist.qml'\n" << testFileUrl("IDontExist.qml")
196             << QString(testFileUrl("IDontExist.qml").toString() + ": File not found");
197 }
198
199 void tst_QQuickLoader::clear()
200 {
201     {
202         QQmlComponent component(&engine);
203         component.setData(QByteArray(
204                     "import QtQuick 2.0\n"
205                     " Loader { id: loader\n"
206                     "  source: 'Rect120x60.qml'\n"
207                     "  Timer { interval: 200; running: true; onTriggered: loader.source = '' }\n"
208                     " }")
209                 , dataDirectoryUrl());
210         QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
211         QVERIFY(loader != 0);
212         QVERIFY(loader->item());
213         QCOMPARE(loader->progress(), 1.0);
214         QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
215
216         QTRY_VERIFY(loader->item() == 0);
217         QCOMPARE(loader->progress(), 0.0);
218         QCOMPARE(loader->status(), QQuickLoader::Null);
219         QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
220
221         delete loader;
222     }
223     {
224         QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
225         QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
226         QVERIFY(item);
227
228         QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
229         QVERIFY(loader);
230         QVERIFY(loader->item());
231         QCOMPARE(loader->progress(), 1.0);
232         QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
233
234         loader->setSourceComponent(0);
235
236         QVERIFY(loader->item() == 0);
237         QCOMPARE(loader->progress(), 0.0);
238         QCOMPARE(loader->status(), QQuickLoader::Null);
239         QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
240
241         delete item;
242     }
243     {
244         QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
245         QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
246         QVERIFY(item);
247
248         QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
249         QVERIFY(loader);
250         QVERIFY(loader->item());
251         QCOMPARE(loader->progress(), 1.0);
252         QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
253
254         QMetaObject::invokeMethod(item, "clear");
255
256         QVERIFY(loader->item() == 0);
257         QCOMPARE(loader->progress(), 0.0);
258         QCOMPARE(loader->status(), QQuickLoader::Null);
259         QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
260
261         delete item;
262     }
263 }
264
265 void tst_QQuickLoader::urlToComponent()
266 {
267     QQmlComponent component(&engine);
268     component.setData(QByteArray("import QtQuick 2.0\n"
269                 "Loader {\n"
270                 " id: loader\n"
271                 " Component { id: myComp; Rectangle { width: 10; height: 10 } }\n"
272                 " source: \"Rect120x60.qml\"\n"
273                 " Timer { interval: 100; running: true; onTriggered: loader.sourceComponent = myComp }\n"
274                 "}" )
275             , dataDirectoryUrl());
276     QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
277     QTest::qWait(200);
278     QTRY_VERIFY(loader != 0);
279     QVERIFY(loader->item());
280     QCOMPARE(loader->progress(), 1.0);
281     QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
282     QCOMPARE(loader->width(), 10.0);
283     QCOMPARE(loader->height(), 10.0);
284
285     delete loader;
286 }
287
288 void tst_QQuickLoader::componentToUrl()
289 {
290     QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
291     QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
292     QVERIFY(item);
293
294     QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
295     QVERIFY(loader);
296     QVERIFY(loader->item());
297     QCOMPARE(loader->progress(), 1.0);
298     QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
299
300     loader->setSource(testFileUrl("/Rect120x60.qml"));
301     QVERIFY(loader->item());
302     QCOMPARE(loader->progress(), 1.0);
303     QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
304     QCOMPARE(loader->width(), 120.0);
305     QCOMPARE(loader->height(), 60.0);
306
307     delete item;
308 }
309
310 void tst_QQuickLoader::anchoredLoader()
311 {
312     QQmlComponent component(&engine, testFileUrl("/AnchoredLoader.qml"));
313     QQuickItem *rootItem = qobject_cast<QQuickItem*>(component.create());
314     QVERIFY(rootItem != 0);
315     QQuickItem *loader = rootItem->findChild<QQuickItem*>("loader");
316     QQuickItem *sourceElement = rootItem->findChild<QQuickItem*>("sourceElement");
317
318     QVERIFY(loader != 0);
319     QVERIFY(sourceElement != 0);
320
321     QCOMPARE(rootItem->width(), 300.0);
322     QCOMPARE(rootItem->height(), 200.0);
323
324     QCOMPARE(loader->width(), 300.0);
325     QCOMPARE(loader->height(), 200.0);
326
327     QCOMPARE(sourceElement->width(), 300.0);
328     QCOMPARE(sourceElement->height(), 200.0);
329 }
330
331 void tst_QQuickLoader::sizeLoaderToItem()
332 {
333     QQmlComponent component(&engine, testFileUrl("/SizeToItem.qml"));
334     QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
335     QVERIFY(loader != 0);
336     QCOMPARE(loader->width(), 120.0);
337     QCOMPARE(loader->height(), 60.0);
338
339     // Check resize
340     QQuickItem *rect = qobject_cast<QQuickItem*>(loader->item());
341     QVERIFY(rect);
342     rect->setWidth(150);
343     rect->setHeight(45);
344     QCOMPARE(loader->width(), 150.0);
345     QCOMPARE(loader->height(), 45.0);
346
347     // Check explicit width
348     loader->setWidth(200.0);
349     QCOMPARE(loader->width(), 200.0);
350     QCOMPARE(rect->width(), 200.0);
351     rect->setWidth(100.0); // when rect changes ...
352     QCOMPARE(rect->width(), 100.0); // ... it changes
353     QCOMPARE(loader->width(), 200.0); // ... but loader stays the same
354
355     // Check explicit height
356     loader->setHeight(200.0);
357     QCOMPARE(loader->height(), 200.0);
358     QCOMPARE(rect->height(), 200.0);
359     rect->setHeight(100.0); // when rect changes ...
360     QCOMPARE(rect->height(), 100.0); // ... it changes
361     QCOMPARE(loader->height(), 200.0); // ... but loader stays the same
362
363     // Switch mode
364     loader->setWidth(180);
365     loader->setHeight(30);
366     QCOMPARE(rect->width(), 180.0);
367     QCOMPARE(rect->height(), 30.0);
368
369     delete loader;
370 }
371
372 void tst_QQuickLoader::sizeItemToLoader()
373 {
374     QQmlComponent component(&engine, testFileUrl("/SizeToLoader.qml"));
375     QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
376     QVERIFY(loader != 0);
377     QCOMPARE(loader->width(), 200.0);
378     QCOMPARE(loader->height(), 80.0);
379
380     QQuickItem *rect = qobject_cast<QQuickItem*>(loader->item());
381     QVERIFY(rect);
382     QCOMPARE(rect->width(), 200.0);
383     QCOMPARE(rect->height(), 80.0);
384
385     // Check resize
386     loader->setWidth(180);
387     loader->setHeight(30);
388     QCOMPARE(rect->width(), 180.0);
389     QCOMPARE(rect->height(), 30.0);
390
391     // Switch mode
392     loader->resetWidth(); // reset explicit size
393     loader->resetHeight();
394     rect->setWidth(160);
395     rect->setHeight(45);
396     QCOMPARE(loader->width(), 160.0);
397     QCOMPARE(loader->height(), 45.0);
398
399     delete loader;
400 }
401
402 void tst_QQuickLoader::noResize()
403 {
404     QQmlComponent component(&engine, testFileUrl("/NoResize.qml"));
405     QQuickItem* item = qobject_cast<QQuickItem*>(component.create());
406     QVERIFY(item != 0);
407     QCOMPARE(item->width(), 200.0);
408     QCOMPARE(item->height(), 80.0);
409
410     delete item;
411 }
412
413 void tst_QQuickLoader::networkRequestUrl()
414 {
415     TestHTTPServer server(SERVER_PORT);
416     QVERIFY(server.isValid());
417     server.serveDirectory(dataDirectory());
418
419     QQmlComponent component(&engine);
420     component.setData(QByteArray("import QtQuick 2.0\nLoader { property int signalCount : 0; source: \"http://127.0.0.1:14450/Rect120x60.qml\"; onLoaded: signalCount += 1 }"), testFileUrl("../dummy.qml"));
421     if (component.isError())
422         qDebug() << component.errors();
423     QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
424     QVERIFY(loader != 0);
425
426     QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
427
428     QVERIFY(loader->item());
429     QCOMPARE(loader->progress(), 1.0);
430     QCOMPARE(loader->property("signalCount").toInt(), 1);
431     QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
432
433     delete loader;
434 }
435
436 /* XXX Component waits until all dependencies are loaded.  Is this actually possible?
437 void tst_QQuickLoader::networkComponent()
438 {
439     TestHTTPServer server(SERVER_PORT);
440     QVERIFY(server.isValid());
441     server.serveDirectory("slowdata", TestHTTPServer::Delay);
442
443     QQmlComponent component(&engine);
444     component.setData(QByteArray(
445                 "import QtQuick 2.0\n"
446                 "import \"http://127.0.0.1:14450/\" as NW\n"
447                 "Item {\n"
448                 " Component { id: comp; NW.SlowRect {} }\n"
449                 " Loader { sourceComponent: comp } }")
450             , dataDirectoryUrl());
451
452     QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
453     QVERIFY(item);
454
455     QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::children().at(1));
456     QVERIFY(loader);
457     QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
458
459     QVERIFY(loader->item());
460     QCOMPARE(loader->progress(), 1.0);
461     QCOMPARE(loader->status(), QQuickLoader::Ready);
462     QCOMPARE(static_cast<QQuickItem*>(loader)->children().count(), 1);
463
464     delete loader;
465 }
466 */
467
468 void tst_QQuickLoader::failNetworkRequest()
469 {
470     TestHTTPServer server(SERVER_PORT);
471     QVERIFY(server.isValid());
472     server.serveDirectory(dataDirectory());
473
474     QTest::ignoreMessage(QtWarningMsg, "http://127.0.0.1:14450/IDontExist.qml: File not found");
475
476     QQmlComponent component(&engine);
477     component.setData(QByteArray("import QtQuick 2.0\nLoader { property int did_load: 123; source: \"http://127.0.0.1:14450/IDontExist.qml\"; onLoaded: did_load=456 }"), QUrl::fromLocalFile("http://127.0.0.1:14450/dummy.qml"));
478     QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
479     QVERIFY(loader != 0);
480
481     QTRY_VERIFY(loader->status() == QQuickLoader::Error);
482
483     QVERIFY(loader->item() == 0);
484     QCOMPARE(loader->progress(), 0.0);
485     QCOMPARE(loader->property("did_load").toInt(), 123);
486     QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
487
488     delete loader;
489 }
490
491 void tst_QQuickLoader::active()
492 {
493     // check that the item isn't instantiated until active is set to true
494     {
495         QQmlComponent component(&engine, testFileUrl("active.1.qml"));
496         QObject *object = component.create();
497         QVERIFY(object != 0);
498         QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
499
500         QVERIFY(loader->active() == false); // set manually to false
501         QVERIFY(loader->item() == 0);
502         QMetaObject::invokeMethod(object, "doSetSourceComponent");
503         QVERIFY(loader->item() == 0);
504         QMetaObject::invokeMethod(object, "doSetSource");
505         QVERIFY(loader->item() == 0);
506         QMetaObject::invokeMethod(object, "doSetActive");
507         QVERIFY(loader->item() != 0);
508
509         delete object;
510     }
511
512     // check that the status is Null if active is set to false
513     {
514         QQmlComponent component(&engine, testFileUrl("active.2.qml"));
515         QObject *object = component.create();
516         QVERIFY(object != 0);
517         QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
518
519         QVERIFY(loader->active() == true); // active is true by default
520         QCOMPARE(loader->status(), QQuickLoader::Ready);
521         int currStatusChangedCount = loader->property("statusChangedCount").toInt();
522         QMetaObject::invokeMethod(object, "doSetInactive");
523         QCOMPARE(loader->status(), QQuickLoader::Null);
524         QCOMPARE(loader->property("statusChangedCount").toInt(), (currStatusChangedCount+1));
525
526         delete object;
527     }
528
529     // check that the source is not cleared if active is set to false
530     {
531         QQmlComponent component(&engine, testFileUrl("active.3.qml"));
532         QObject *object = component.create();
533         QVERIFY(object != 0);
534         QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
535
536         QVERIFY(loader->active() == true); // active is true by default
537         QVERIFY(!loader->source().isEmpty());
538         int currSourceChangedCount = loader->property("sourceChangedCount").toInt();
539         QMetaObject::invokeMethod(object, "doSetInactive");
540         QVERIFY(!loader->source().isEmpty());
541         QCOMPARE(loader->property("sourceChangedCount").toInt(), currSourceChangedCount);
542
543         delete object;
544     }
545
546     // check that the sourceComponent is not cleared if active is set to false
547     {
548         QQmlComponent component(&engine, testFileUrl("active.4.qml"));
549         QObject *object = component.create();
550         QVERIFY(object != 0);
551         QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
552
553         QVERIFY(loader->active() == true); // active is true by default
554         QVERIFY(loader->sourceComponent() != 0);
555         int currSourceComponentChangedCount = loader->property("sourceComponentChangedCount").toInt();
556         QMetaObject::invokeMethod(object, "doSetInactive");
557         QVERIFY(loader->sourceComponent() != 0);
558         QCOMPARE(loader->property("sourceComponentChangedCount").toInt(), currSourceComponentChangedCount);
559
560         delete object;
561     }
562
563     // check that the item is released if active is set to false
564     {
565         QQmlComponent component(&engine, testFileUrl("active.5.qml"));
566         QObject *object = component.create();
567         QVERIFY(object != 0);
568         QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
569
570         QVERIFY(loader->active() == true); // active is true by default
571         QVERIFY(loader->item() != 0);
572         int currItemChangedCount = loader->property("itemChangedCount").toInt();
573         QMetaObject::invokeMethod(object, "doSetInactive");
574         QVERIFY(loader->item() == 0);
575         QCOMPARE(loader->property("itemChangedCount").toInt(), (currItemChangedCount+1));
576
577         delete object;
578     }
579
580     // check that the activeChanged signal is emitted correctly
581     {
582         QQmlComponent component(&engine, testFileUrl("active.6.qml"));
583         QObject *object = component.create();
584         QVERIFY(object != 0);
585         QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
586
587         QVERIFY(loader->active() == true); // active is true by default
588         loader->setActive(true);           // no effect
589         QCOMPARE(loader->property("activeChangedCount").toInt(), 0);
590         loader->setActive(false);          // change signal should be emitted
591         QCOMPARE(loader->property("activeChangedCount").toInt(), 1);
592         loader->setActive(false);          // no effect
593         QCOMPARE(loader->property("activeChangedCount").toInt(), 1);
594         loader->setActive(true);           // change signal should be emitted
595         QCOMPARE(loader->property("activeChangedCount").toInt(), 2);
596         loader->setActive(false);          // change signal should be emitted
597         QCOMPARE(loader->property("activeChangedCount").toInt(), 3);
598         QMetaObject::invokeMethod(object, "doSetActive");
599         QCOMPARE(loader->property("activeChangedCount").toInt(), 4);
600         QMetaObject::invokeMethod(object, "doSetActive");
601         QCOMPARE(loader->property("activeChangedCount").toInt(), 4);
602         QMetaObject::invokeMethod(object, "doSetInactive");
603         QCOMPARE(loader->property("activeChangedCount").toInt(), 5);
604         loader->setActive(true);           // change signal should be emitted
605         QCOMPARE(loader->property("activeChangedCount").toInt(), 6);
606
607         delete object;
608     }
609
610     // check that the component isn't loaded until active is set to true
611     {
612         QQmlComponent component(&engine, testFileUrl("active.7.qml"));
613         QObject *object = component.create();
614         QVERIFY(object != 0);
615         QCOMPARE(object->property("success").toBool(), true);
616         delete object;
617     }
618
619     // check that the component is loaded if active is not set (true by default)
620     {
621         QQmlComponent component(&engine, testFileUrl("active.8.qml"));
622         QObject *object = component.create();
623         QVERIFY(object != 0);
624         QCOMPARE(object->property("success").toBool(), true);
625         delete object;
626     }
627 }
628
629 void tst_QQuickLoader::initialPropertyValues_data()
630 {
631     QTest::addColumn<QUrl>("qmlFile");
632     QTest::addColumn<QStringList>("expectedWarnings");
633     QTest::addColumn<QStringList>("propertyNames");
634     QTest::addColumn<QVariantList>("propertyValues");
635
636     QTest::newRow("source url with value set in onLoaded, initially active = true") << testFileUrl("initialPropertyValues.1.qml")
637             << QStringList()
638             << (QStringList() << "initialValue" << "behaviorCount")
639             << (QVariantList() << 1 << 1);
640
641     QTest::newRow("set source with initial property values specified, active = true") << testFileUrl("initialPropertyValues.2.qml")
642             << QStringList()
643             << (QStringList() << "initialValue" << "behaviorCount")
644             << (QVariantList() << 2 << 0);
645
646     QTest::newRow("set source with initial property values specified, active = false") << testFileUrl("initialPropertyValues.3.qml")
647             << (QStringList() << QString(QLatin1String("file://") + testFileUrl("initialPropertyValues.3.qml").toLocalFile() + QLatin1String(":16: TypeError: Cannot read property 'canary' of null")))
648             << (QStringList())
649             << (QVariantList());
650
651     QTest::newRow("set source with initial property values specified, active = false, with active set true later") << testFileUrl("initialPropertyValues.4.qml")
652             << QStringList()
653             << (QStringList() << "initialValue" << "behaviorCount")
654             << (QVariantList() << 4 << 0);
655
656     QTest::newRow("set source without initial property values specified, active = true") << testFileUrl("initialPropertyValues.5.qml")
657             << QStringList()
658             << (QStringList() << "initialValue" << "behaviorCount")
659             << (QVariantList() << 0 << 0);
660
661     QTest::newRow("set source with initial property values specified with binding, active = true") << testFileUrl("initialPropertyValues.6.qml")
662             << QStringList()
663             << (QStringList() << "initialValue" << "behaviorCount")
664             << (QVariantList() << 6 << 0);
665
666     QTest::newRow("ensure initial property value semantics mimic createObject") << testFileUrl("initialPropertyValues.7.qml")
667             << QStringList()
668             << (QStringList() << "loaderValue" << "createObjectValue")
669             << (QVariantList() << 1 << 1);
670
671     QTest::newRow("ensure initial property values aren't disposed prior to component completion") << testFileUrl("initialPropertyValues.8.qml")
672             << QStringList()
673             << (QStringList() << "initialValue")
674             << (QVariantList() << 6);
675 }
676
677 void tst_QQuickLoader::initialPropertyValues()
678 {
679     QFETCH(QUrl, qmlFile);
680     QFETCH(QStringList, expectedWarnings);
681     QFETCH(QStringList, propertyNames);
682     QFETCH(QVariantList, propertyValues);
683
684     TestHTTPServer server(SERVER_PORT);
685     QVERIFY(server.isValid());
686     server.serveDirectory(dataDirectory());
687
688     foreach (const QString &warning, expectedWarnings)
689         QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
690
691     QQmlComponent component(&engine, qmlFile);
692     QObject *object = component.create();
693     QVERIFY(object != 0);
694     qApp->processEvents();
695     QTest::qWait(50);
696
697     for (int i = 0; i < propertyNames.size(); ++i)
698         QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
699
700     delete object;
701 }
702
703 void tst_QQuickLoader::initialPropertyValuesBinding()
704 {
705     QQmlComponent component(&engine, testFileUrl("initialPropertyValues.binding.qml"));
706     QObject *object = component.create();
707     QVERIFY(object != 0);
708
709     QVERIFY(object->setProperty("bindable", QVariant(8)));
710     QCOMPARE(object->property("canaryValue").toInt(), 8);
711
712     delete object;
713 }
714
715 void tst_QQuickLoader::initialPropertyValuesError_data()
716 {
717     QTest::addColumn<QUrl>("qmlFile");
718     QTest::addColumn<QStringList>("expectedWarnings");
719
720     QTest::newRow("invalid initial property values object") << testFileUrl("initialPropertyValues.error.1.qml")
721             << (QStringList() << QString(testFileUrl("initialPropertyValues.error.1.qml").toString() + ":6:5: QML Loader: setSource: value is not an object"));
722
723     QTest::newRow("nonexistent source url") << testFileUrl("initialPropertyValues.error.2.qml")
724             << (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": File not found"));
725
726     QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml")
727             << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
728
729     QTest::newRow("invalid initial property values object with invalid property access") << testFileUrl("initialPropertyValues.error.4.qml")
730             << (QStringList() << QString(testFileUrl("initialPropertyValues.error.4.qml").toString() + ":7:5: QML Loader: setSource: value is not an object")
731                               << QString(testFileUrl("initialPropertyValues.error.4.qml").toString() + ":5: TypeError: Cannot read property 'canary' of null"));
732 }
733
734 void tst_QQuickLoader::initialPropertyValuesError()
735 {
736     QFETCH(QUrl, qmlFile);
737     QFETCH(QStringList, expectedWarnings);
738
739     foreach (const QString &warning, expectedWarnings)
740         QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
741
742     QQmlComponent component(&engine, qmlFile);
743     QObject *object = component.create();
744     QVERIFY(object != 0);
745     QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
746     QVERIFY(loader != 0);
747     QVERIFY(loader->item() == 0);
748     delete object;
749 }
750
751 // QTBUG-9241
752 void tst_QQuickLoader::deleteComponentCrash()
753 {
754     QQmlComponent component(&engine, testFileUrl("crash.qml"));
755     QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
756     QVERIFY(item);
757
758     item->metaObject()->invokeMethod(item, "setLoaderSource");
759
760     QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
761     QVERIFY(loader);
762     QVERIFY(loader->item());
763     QCOMPARE(loader->item()->objectName(), QLatin1String("blue"));
764     QCOMPARE(loader->progress(), 1.0);
765     QCOMPARE(loader->status(), QQuickLoader::Ready);
766     QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
767     QCoreApplication::processEvents();
768     QTRY_COMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
769     QVERIFY(loader->source() == testFileUrl("BlueRect.qml"));
770
771     delete item;
772 }
773
774 void tst_QQuickLoader::nonItem()
775 {
776     QQmlComponent component(&engine, testFileUrl("nonItem.qml"));
777     QString err = testFileUrl("nonItem.qml").toString() + ":3:1: QML Loader: Loader does not support loading non-visual elements.";
778
779     QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
780     QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
781     QVERIFY(loader);
782     QVERIFY(loader->item() == 0);
783
784     delete loader;
785 }
786
787 void tst_QQuickLoader::vmeErrors()
788 {
789     QQmlComponent component(&engine, testFileUrl("vmeErrors.qml"));
790     QString err = testFileUrl("VmeError.qml").toString() + ":6: Cannot assign object type QObject with no default method";
791     QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
792     QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
793     QVERIFY(loader);
794     QVERIFY(loader->item() == 0);
795
796     delete loader;
797 }
798
799 // QTBUG-13481
800 void tst_QQuickLoader::creationContext()
801 {
802     QQmlComponent component(&engine, testFileUrl("creationContext.qml"));
803
804     QObject *o = component.create();
805     QVERIFY(o != 0);
806
807     QCOMPARE(o->property("test").toBool(), true);
808
809     delete o;
810 }
811
812 void tst_QQuickLoader::QTBUG_16928()
813 {
814     QQmlComponent component(&engine, testFileUrl("QTBUG_16928.qml"));
815     QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
816     QVERIFY(item);
817
818     QCOMPARE(item->width(), 250.);
819     QCOMPARE(item->height(), 250.);
820
821     delete item;
822 }
823
824 void tst_QQuickLoader::implicitSize()
825 {
826     QQmlComponent component(&engine, testFileUrl("implicitSize.qml"));
827     QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
828     QVERIFY(item);
829
830     QCOMPARE(item->width(), 150.);
831     QCOMPARE(item->height(), 150.);
832
833     QCOMPARE(item->property("implHeight").toReal(), 100.);
834     QCOMPARE(item->property("implWidth").toReal(), 100.);
835
836     delete item;
837 }
838
839 void tst_QQuickLoader::QTBUG_17114()
840 {
841     QQmlComponent component(&engine, testFileUrl("QTBUG_17114.qml"));
842     QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
843     QVERIFY(item);
844
845     QCOMPARE(item->property("loaderWidth").toReal(), 32.);
846     QCOMPARE(item->property("loaderHeight").toReal(), 32.);
847
848     delete item;
849 }
850
851 void tst_QQuickLoader::asynchronous_data()
852 {
853     QTest::addColumn<QUrl>("qmlFile");
854     QTest::addColumn<QStringList>("expectedWarnings");
855
856     QTest::newRow("Valid component") << testFileUrl("BigComponent.qml")
857             << QStringList();
858
859     QTest::newRow("Non-existant component") << testFileUrl("IDoNotExist.qml")
860             << (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": File not found"));
861
862     QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml")
863             << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
864 }
865
866 void tst_QQuickLoader::asynchronous()
867 {
868     QFETCH(QUrl, qmlFile);
869     QFETCH(QStringList, expectedWarnings);
870
871     if (!engine.incubationController())
872         engine.setIncubationController(new PeriodicIncubationController);
873     QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
874     QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
875     QVERIFY(root);
876
877     QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
878     QVERIFY(loader);
879
880     foreach (const QString &warning, expectedWarnings)
881         QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
882
883     QVERIFY(!loader->item());
884     root->setProperty("comp", qmlFile.toString());
885     QMetaObject::invokeMethod(root, "loadComponent");
886     QVERIFY(!loader->item());
887
888     if (expectedWarnings.isEmpty()) {
889         QCOMPARE(loader->status(), QQuickLoader::Loading);
890         QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
891
892         QTRY_VERIFY(loader->item());
893         QCOMPARE(loader->progress(), 1.0);
894         QCOMPARE(loader->status(), QQuickLoader::Ready);
895     } else {
896         QCOMPARE(loader->progress(), 1.0);
897         QTRY_COMPARE(loader->status(), QQuickLoader::Error);
898     }
899
900     delete root;
901 }
902
903 void tst_QQuickLoader::asynchronous_clear()
904 {
905     if (!engine.incubationController())
906         engine.setIncubationController(new PeriodicIncubationController);
907     QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
908     QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
909     QVERIFY(root);
910
911     QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
912     QVERIFY(loader);
913
914     QVERIFY(!loader->item());
915     root->setProperty("comp", "BigComponent.qml");
916     QMetaObject::invokeMethod(root, "loadComponent");
917     QVERIFY(!loader->item());
918
919     QCOMPARE(loader->status(), QQuickLoader::Loading);
920     QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
921
922     // clear before component created
923     root->setProperty("comp", "");
924     QMetaObject::invokeMethod(root, "loadComponent");
925     QVERIFY(!loader->item());
926     QCOMPARE(engine.incubationController()->incubatingObjectCount(), 0);
927
928     QCOMPARE(loader->progress(), 0.0);
929     QCOMPARE(loader->status(), QQuickLoader::Null);
930     QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
931
932     // check loading component
933     root->setProperty("comp", "Rect120x60.qml");
934     QMetaObject::invokeMethod(root, "loadComponent");
935     QVERIFY(!loader->item());
936
937     QCOMPARE(loader->status(), QQuickLoader::Loading);
938     QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
939
940     QTRY_VERIFY(loader->item());
941     QCOMPARE(loader->progress(), 1.0);
942     QCOMPARE(loader->status(), QQuickLoader::Ready);
943     QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
944 }
945
946 void tst_QQuickLoader::parented()
947 {
948     QQmlComponent component(&engine, testFileUrl("parented.qml"));
949     QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
950     QVERIFY(root);
951
952     QQuickItem *item = root->findChild<QQuickItem*>("comp");
953     QVERIFY(item);
954
955     QVERIFY(item->parentItem() == root);
956
957     QCOMPARE(item->width(), 300.);
958     QCOMPARE(item->height(), 300.);
959
960     delete root;
961 }
962
963 void tst_QQuickLoader::sizeBound()
964 {
965     QQmlComponent component(&engine, testFileUrl("sizebound.qml"));
966     QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
967     QVERIFY(root);
968     QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
969     QVERIFY(loader != 0);
970
971     QVERIFY(loader->item());
972
973     QCOMPARE(loader->width(), 50.0);
974     QCOMPARE(loader->height(), 60.0);
975
976     QMetaObject::invokeMethod(root, "switchComponent");
977
978     QCOMPARE(loader->width(), 80.0);
979     QCOMPARE(loader->height(), 90.0);
980
981     delete root;
982 }
983
984
985 QTEST_MAIN(tst_QQuickLoader)
986
987 #include "tst_qquickloader.moc"