1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
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"
53 #define SERVER_PORT 14450
55 inline QUrl TEST_FILE(const QString &filename)
57 return QUrl::fromLocalFile(TESTDATA(filename));
60 class PeriodicIncubationController : public QObject,
61 public QDeclarativeIncubationController
64 PeriodicIncubationController() {
69 virtual void timerEvent(QTimerEvent *) {
74 class tst_QSGLoader : public QObject
82 void sourceOrComponent();
83 void sourceOrComponent_data();
85 void urlToComponent();
86 void componentToUrl();
87 void anchoredLoader();
88 void sizeLoaderToItem();
89 void sizeItemToLoader();
91 void networkRequestUrl();
92 void failNetworkRequest();
93 // void networkComponent();
95 void initialPropertyValues_data();
96 void initialPropertyValues();
97 void initialPropertyValuesBinding();
98 void initialPropertyValuesError_data();
99 void initialPropertyValuesError();
101 void deleteComponentCrash();
104 void creationContext();
108 void asynchronous_data();
110 void asynchronous_clear();
113 QDeclarativeEngine engine;
117 tst_QSGLoader::tst_QSGLoader()
121 void tst_QSGLoader::sourceOrComponent()
123 QFETCH(QString, sourceOrComponent);
124 QFETCH(QString, sourceDefinition);
125 QFETCH(QUrl, sourceUrl);
126 QFETCH(QString, errorString);
128 bool error = !errorString.isEmpty();
130 QTest::ignoreMessage(QtWarningMsg, errorString.toUtf8().constData());
132 QDeclarativeComponent component(&engine);
133 component.setData(QByteArray(
134 "import QtQuick 2.0\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()
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"
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);
159 QCOMPARE(loader->status(), error ? QSGLoader::Error : QSGLoader::Ready);
160 QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), error ? 0: 1);
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;
170 QVERIFY(sourceComponentIsChildOfLoader);
173 if (sourceOrComponent == "component") {
174 QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 1);
175 QCOMPARE(loader->property("onSourceChangedCount").toInt(), 0);
177 QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 0);
178 QCOMPARE(loader->property("onSourceChangedCount").toInt(), 1);
180 QCOMPARE(loader->property("onStatusChangedCount").toInt(), 1);
181 QCOMPARE(loader->property("onProgressChangedCount").toInt(), 1);
183 QCOMPARE(loader->property("onItemChangedCount").toInt(), error ? 0 : 1);
184 QCOMPARE(loader->property("onLoadedCount").toInt(), error ? 0 : 1);
189 void tst_QSGLoader::sourceOrComponent_data()
191 QTest::addColumn<QString>("sourceOrComponent");
192 QTest::addColumn<QString>("sourceDefinition");
193 QTest::addColumn<QUrl>("sourceUrl");
194 QTest::addColumn<QString>("errorString");
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");
202 void tst_QSGLoader::clear()
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"
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);
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);
227 QDeclarativeComponent component(&engine, TEST_FILE("/SetSourceComponent.qml"));
228 QSGItem *item = qobject_cast<QSGItem*>(component.create());
231 QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::childItems().at(0));
233 QVERIFY(loader->item());
234 QCOMPARE(loader->progress(), 1.0);
235 QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
237 loader->setSourceComponent(0);
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);
247 QDeclarativeComponent component(&engine, TEST_FILE("/SetSourceComponent.qml"));
248 QSGItem *item = qobject_cast<QSGItem*>(component.create());
251 QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::childItems().at(0));
253 QVERIFY(loader->item());
254 QCOMPARE(loader->progress(), 1.0);
255 QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
257 QMetaObject::invokeMethod(item, "clear");
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);
268 void tst_QSGLoader::urlToComponent()
270 QDeclarativeComponent component(&engine);
271 component.setData(QByteArray("import QtQuick 2.0\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"
279 QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
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);
291 void tst_QSGLoader::componentToUrl()
293 QDeclarativeComponent component(&engine, TEST_FILE("/SetSourceComponent.qml"));
294 QSGItem *item = qobject_cast<QSGItem*>(component.create());
297 QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::childItems().at(0));
299 QVERIFY(loader->item());
300 QCOMPARE(loader->progress(), 1.0);
301 QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 1);
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);
313 void tst_QSGLoader::anchoredLoader()
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");
321 QVERIFY(loader != 0);
322 QVERIFY(sourceElement != 0);
324 QCOMPARE(rootItem->width(), 300.0);
325 QCOMPARE(rootItem->height(), 200.0);
327 QCOMPARE(loader->width(), 300.0);
328 QCOMPARE(loader->height(), 200.0);
330 QCOMPARE(sourceElement->width(), 300.0);
331 QCOMPARE(sourceElement->height(), 200.0);
334 void tst_QSGLoader::sizeLoaderToItem()
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);
343 QSGItem *rect = qobject_cast<QSGItem*>(loader->item());
347 QCOMPARE(loader->width(), 150.0);
348 QCOMPARE(loader->height(), 45.0);
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
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
367 loader->setWidth(180);
368 loader->setHeight(30);
369 QCOMPARE(rect->width(), 180.0);
370 QCOMPARE(rect->height(), 30.0);
375 void tst_QSGLoader::sizeItemToLoader()
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);
383 QSGItem *rect = qobject_cast<QSGItem*>(loader->item());
385 QCOMPARE(rect->width(), 200.0);
386 QCOMPARE(rect->height(), 80.0);
389 loader->setWidth(180);
390 loader->setHeight(30);
391 QCOMPARE(rect->width(), 180.0);
392 QCOMPARE(rect->height(), 30.0);
395 loader->resetWidth(); // reset explicit size
396 loader->resetHeight();
399 QCOMPARE(loader->width(), 160.0);
400 QCOMPARE(loader->height(), 45.0);
405 void tst_QSGLoader::noResize()
407 QDeclarativeComponent component(&engine, TEST_FILE("/NoResize.qml"));
408 QSGItem* item = qobject_cast<QSGItem*>(component.create());
410 QCOMPARE(item->width(), 200.0);
411 QCOMPARE(item->height(), 80.0);
416 void tst_QSGLoader::networkRequestUrl()
418 TestHTTPServer server(SERVER_PORT);
419 QVERIFY(server.isValid());
420 server.serveDirectory(TESTDATA(""));
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);
429 QTRY_VERIFY(loader->status() == QSGLoader::Ready);
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);
439 /* XXX Component waits until all dependencies are loaded. Is this actually possible?
440 void tst_QSGLoader::networkComponent()
442 TestHTTPServer server(SERVER_PORT);
443 QVERIFY(server.isValid());
444 server.serveDirectory("slowdata", TestHTTPServer::Delay);
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"
451 " Component { id: comp; NW.SlowRect {} }\n"
452 " Loader { sourceComponent: comp } }")
455 QSGItem *item = qobject_cast<QSGItem*>(component.create());
458 QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::children().at(1));
460 QTRY_VERIFY(loader->status() == QSGLoader::Ready);
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);
471 void tst_QSGLoader::failNetworkRequest()
473 TestHTTPServer server(SERVER_PORT);
474 QVERIFY(server.isValid());
475 server.serveDirectory(TESTDATA(""));
477 QTest::ignoreMessage(QtWarningMsg, "http://127.0.0.1:14450/IDontExist.qml: File not found");
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);
484 QTRY_VERIFY(loader->status() == QSGLoader::Error);
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);
494 void tst_QSGLoader::active()
496 // check that the item isn't instantiated until active is set to true
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");
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);
515 // check that the status is Null if active is set to false
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");
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));
532 // check that the source is not cleared if active is set to false
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");
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);
549 // check that the sourceComponent is not cleared if active is set to false
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");
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);
566 // check that the item is released if active is set to false
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");
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));
583 // check that the activeChanged signal is emitted correctly
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");
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);
613 // check that the component isn't loaded until active is set to true
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);
622 // check that the component is loaded if active is not set (true by default)
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);
632 void tst_QSGLoader::initialPropertyValues_data()
634 QTest::addColumn<QUrl>("qmlFile");
635 QTest::addColumn<QStringList>("expectedWarnings");
636 QTest::addColumn<QStringList>("propertyNames");
637 QTest::addColumn<QVariantList>("propertyValues");
639 QTest::newRow("source url with value set in onLoaded, initially active = true") << TEST_FILE("initialPropertyValues.1.qml")
641 << (QStringList() << "initialValue" << "behaviorCount")
642 << (QVariantList() << 1 << 1);
644 QTest::newRow("set source with initial property values specified, active = true") << TEST_FILE("initialPropertyValues.2.qml")
646 << (QStringList() << "initialValue" << "behaviorCount")
647 << (QVariantList() << 2 << 0);
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")))
654 QTest::newRow("set source with initial property values specified, active = false, with active set true later") << TEST_FILE("initialPropertyValues.4.qml")
656 << (QStringList() << "initialValue" << "behaviorCount")
657 << (QVariantList() << 4 << 0);
659 QTest::newRow("set source without initial property values specified, active = true") << TEST_FILE("initialPropertyValues.5.qml")
661 << (QStringList() << "initialValue" << "behaviorCount")
662 << (QVariantList() << 0 << 0);
664 QTest::newRow("set source with initial property values specified with binding, active = true") << TEST_FILE("initialPropertyValues.6.qml")
666 << (QStringList() << "initialValue" << "behaviorCount")
667 << (QVariantList() << 6 << 0);
669 QTest::newRow("ensure initial property value semantics mimic createObject") << TEST_FILE("initialPropertyValues.7.qml")
671 << (QStringList() << "loaderValue" << "createObjectValue")
672 << (QVariantList() << 1 << 1);
674 QTest::newRow("ensure initial property values aren't disposed prior to component completion") << TEST_FILE("initialPropertyValues.8.qml")
676 << (QStringList() << "initialValue")
677 << (QVariantList() << 6);
680 void tst_QSGLoader::initialPropertyValues()
682 QFETCH(QUrl, qmlFile);
683 QFETCH(QStringList, expectedWarnings);
684 QFETCH(QStringList, propertyNames);
685 QFETCH(QVariantList, propertyValues);
687 TestHTTPServer server(SERVER_PORT);
688 QVERIFY(server.isValid());
689 server.serveDirectory(TESTDATA(""));
691 foreach (const QString &warning, expectedWarnings)
692 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
694 QDeclarativeComponent component(&engine, qmlFile);
695 QObject *object = component.create();
696 QVERIFY(object != 0);
697 qApp->processEvents();
700 for (int i = 0; i < propertyNames.size(); ++i)
701 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
706 void tst_QSGLoader::initialPropertyValuesBinding()
708 QDeclarativeComponent component(&engine, TEST_FILE("initialPropertyValues.binding.qml"));
709 QObject *object = component.create();
710 QVERIFY(object != 0);
712 QVERIFY(object->setProperty("bindable", QVariant(8)));
713 QCOMPARE(object->property("canaryValue").toInt(), 8);
718 void tst_QSGLoader::initialPropertyValuesError_data()
720 QTest::addColumn<QUrl>("qmlFile");
721 QTest::addColumn<QStringList>("expectedWarnings");
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"));
726 QTest::newRow("nonexistent source url") << TEST_FILE("initialPropertyValues.error.2.qml")
727 << (QStringList() << QString(TEST_FILE("NonexistentSourceComponent.qml").toString() + ": File not found"));
729 QTest::newRow("invalid source url") << TEST_FILE("initialPropertyValues.error.3.qml")
730 << (QStringList() << QString(TEST_FILE("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
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"));
737 void tst_QSGLoader::initialPropertyValuesError()
739 QFETCH(QUrl, qmlFile);
740 QFETCH(QStringList, expectedWarnings);
742 foreach (const QString &warning, expectedWarnings)
743 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
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);
755 void tst_QSGLoader::deleteComponentCrash()
757 QDeclarativeComponent component(&engine, TEST_FILE("crash.qml"));
758 QSGItem *item = qobject_cast<QSGItem*>(component.create());
761 item->metaObject()->invokeMethod(item, "setLoaderSource");
763 QSGLoader *loader = qobject_cast<QSGLoader*>(item->QSGItem::childItems().at(0));
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")));
776 void tst_QSGLoader::nonItem()
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.";
781 QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
782 QSGLoader *loader = qobject_cast<QSGLoader*>(component.create());
784 QVERIFY(loader->item() == 0);
789 void tst_QSGLoader::vmeErrors()
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());
796 QVERIFY(loader->item() == 0);
802 void tst_QSGLoader::creationContext()
804 QDeclarativeComponent component(&engine, TEST_FILE("creationContext.qml"));
806 QObject *o = component.create();
809 QCOMPARE(o->property("test").toBool(), true);
814 void tst_QSGLoader::QTBUG_16928()
816 QDeclarativeComponent component(&engine, TEST_FILE("QTBUG_16928.qml"));
817 QSGItem *item = qobject_cast<QSGItem*>(component.create());
820 QCOMPARE(item->width(), 250.);
821 QCOMPARE(item->height(), 250.);
826 void tst_QSGLoader::implicitSize()
828 QDeclarativeComponent component(&engine, TEST_FILE("implicitSize.qml"));
829 QSGItem *item = qobject_cast<QSGItem*>(component.create());
832 QCOMPARE(item->width(), 150.);
833 QCOMPARE(item->height(), 150.);
835 QCOMPARE(item->property("implHeight").toReal(), 100.);
836 QCOMPARE(item->property("implWidth").toReal(), 100.);
841 void tst_QSGLoader::QTBUG_17114()
843 QDeclarativeComponent component(&engine, TEST_FILE("QTBUG_17114.qml"));
844 QSGItem *item = qobject_cast<QSGItem*>(component.create());
847 QCOMPARE(item->property("loaderWidth").toReal(), 32.);
848 QCOMPARE(item->property("loaderHeight").toReal(), 32.);
853 void tst_QSGLoader::asynchronous_data()
855 QTest::addColumn<QUrl>("qmlFile");
856 QTest::addColumn<QStringList>("expectedWarnings");
858 QTest::newRow("Valid component") << TEST_FILE("BigComponent.qml")
861 QTest::newRow("Non-existant component") << TEST_FILE("IDoNotExist.qml")
862 << (QStringList() << QString(TEST_FILE("IDoNotExist.qml").toString() + ": File not found"));
864 QTest::newRow("Invalid component") << TEST_FILE("InvalidSourceComponent.qml")
865 << (QStringList() << QString(TEST_FILE("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
868 void tst_QSGLoader::asynchronous()
870 QFETCH(QUrl, qmlFile);
871 QFETCH(QStringList, expectedWarnings);
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());
879 QSGLoader *loader = root->findChild<QSGLoader*>("loader");
882 foreach (const QString &warning, expectedWarnings)
883 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
885 QVERIFY(!loader->item());
886 root->setProperty("comp", qmlFile.toString());
887 QMetaObject::invokeMethod(root, "loadComponent");
888 QVERIFY(!loader->item());
890 if (expectedWarnings.isEmpty()) {
891 QCOMPARE(loader->status(), QSGLoader::Loading);
892 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
894 QTRY_VERIFY(loader->item());
895 QCOMPARE(loader->progress(), 1.0);
896 QCOMPARE(loader->status(), QSGLoader::Ready);
898 QCOMPARE(loader->progress(), 1.0);
899 QTRY_COMPARE(loader->status(), QSGLoader::Error);
905 void tst_QSGLoader::asynchronous_clear()
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());
913 QSGLoader *loader = root->findChild<QSGLoader*>("loader");
916 QVERIFY(!loader->item());
917 root->setProperty("comp", "BigComponent.qml");
918 QMetaObject::invokeMethod(root, "loadComponent");
919 QVERIFY(!loader->item());
921 QCOMPARE(loader->status(), QSGLoader::Loading);
922 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
924 // clear before component created
925 root->setProperty("comp", "");
926 QMetaObject::invokeMethod(root, "loadComponent");
927 QVERIFY(!loader->item());
928 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 0);
930 QCOMPARE(loader->progress(), 0.0);
931 QCOMPARE(loader->status(), QSGLoader::Null);
932 QCOMPARE(static_cast<QSGItem*>(loader)->childItems().count(), 0);
934 // check loading component
935 root->setProperty("comp", "Rect120x60.qml");
936 QMetaObject::invokeMethod(root, "loadComponent");
937 QVERIFY(!loader->item());
939 QCOMPARE(loader->status(), QSGLoader::Loading);
940 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
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);
949 QTEST_MAIN(tst_QSGLoader)
951 #include "tst_qsgloader.moc"