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