1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
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"
52 #define SERVER_PORT 14450
54 class PeriodicIncubationController : public QObject,
55 public QQmlIncubationController
58 PeriodicIncubationController() {
63 virtual void timerEvent(QTimerEvent *) {
68 class tst_QQuickLoader : public QQmlDataTest
76 void sourceOrComponent();
77 void sourceOrComponent_data();
79 void urlToComponent();
80 void componentToUrl();
81 void anchoredLoader();
82 void sizeLoaderToItem();
83 void sizeItemToLoader();
85 void networkRequestUrl();
86 void failNetworkRequest();
87 // void networkComponent();
89 void initialPropertyValues_data();
90 void initialPropertyValues();
91 void initialPropertyValuesBinding();
92 void initialPropertyValuesError_data();
93 void initialPropertyValuesError();
95 void deleteComponentCrash();
98 void creationContext();
102 void asynchronous_data();
104 void asynchronous_clear();
114 tst_QQuickLoader::tst_QQuickLoader()
118 void tst_QQuickLoader::sourceOrComponent()
120 QFETCH(QString, sourceOrComponent);
121 QFETCH(QString, sourceDefinition);
122 QFETCH(QUrl, sourceUrl);
123 QFETCH(QString, errorString);
125 bool error = !errorString.isEmpty();
127 QTest::ignoreMessage(QtWarningMsg, errorString.toUtf8().constData());
129 QQmlComponent component(&engine);
130 component.setData(QByteArray(
131 "import QtQuick 2.0\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()
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"
148 , dataDirectoryUrl());
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);
156 QCOMPARE(loader->status(), error ? QQuickLoader::Error : QQuickLoader::Ready);
157 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), error ? 0: 1);
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;
167 QVERIFY(sourceComponentIsChildOfLoader);
170 if (sourceOrComponent == "component") {
171 QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 1);
172 QCOMPARE(loader->property("onSourceChangedCount").toInt(), 0);
174 QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 0);
175 QCOMPARE(loader->property("onSourceChangedCount").toInt(), 1);
177 QCOMPARE(loader->property("onStatusChangedCount").toInt(), 1);
178 QCOMPARE(loader->property("onProgressChangedCount").toInt(), 1);
180 QCOMPARE(loader->property("onItemChangedCount").toInt(), error ? 0 : 1);
181 QCOMPARE(loader->property("onLoadedCount").toInt(), error ? 0 : 1);
186 void tst_QQuickLoader::sourceOrComponent_data()
188 QTest::addColumn<QString>("sourceOrComponent");
189 QTest::addColumn<QString>("sourceDefinition");
190 QTest::addColumn<QUrl>("sourceUrl");
191 QTest::addColumn<QString>("errorString");
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");
199 void tst_QQuickLoader::clear()
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"
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);
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);
224 QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
225 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
228 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
230 QVERIFY(loader->item());
231 QCOMPARE(loader->progress(), 1.0);
232 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
234 loader->setSourceComponent(0);
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);
244 QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
245 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
248 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
250 QVERIFY(loader->item());
251 QCOMPARE(loader->progress(), 1.0);
252 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
254 QMetaObject::invokeMethod(item, "clear");
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);
265 void tst_QQuickLoader::urlToComponent()
267 QQmlComponent component(&engine);
268 component.setData(QByteArray("import QtQuick 2.0\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"
275 , dataDirectoryUrl());
276 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
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);
288 void tst_QQuickLoader::componentToUrl()
290 QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
291 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
294 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
296 QVERIFY(loader->item());
297 QCOMPARE(loader->progress(), 1.0);
298 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
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);
310 void tst_QQuickLoader::anchoredLoader()
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");
318 QVERIFY(loader != 0);
319 QVERIFY(sourceElement != 0);
321 QCOMPARE(rootItem->width(), 300.0);
322 QCOMPARE(rootItem->height(), 200.0);
324 QCOMPARE(loader->width(), 300.0);
325 QCOMPARE(loader->height(), 200.0);
327 QCOMPARE(sourceElement->width(), 300.0);
328 QCOMPARE(sourceElement->height(), 200.0);
331 void tst_QQuickLoader::sizeLoaderToItem()
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);
340 QQuickItem *rect = qobject_cast<QQuickItem*>(loader->item());
344 QCOMPARE(loader->width(), 150.0);
345 QCOMPARE(loader->height(), 45.0);
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
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
364 loader->setWidth(180);
365 loader->setHeight(30);
366 QCOMPARE(rect->width(), 180.0);
367 QCOMPARE(rect->height(), 30.0);
372 void tst_QQuickLoader::sizeItemToLoader()
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);
380 QQuickItem *rect = qobject_cast<QQuickItem*>(loader->item());
382 QCOMPARE(rect->width(), 200.0);
383 QCOMPARE(rect->height(), 80.0);
386 loader->setWidth(180);
387 loader->setHeight(30);
388 QCOMPARE(rect->width(), 180.0);
389 QCOMPARE(rect->height(), 30.0);
392 loader->resetWidth(); // reset explicit size
393 loader->resetHeight();
396 QCOMPARE(loader->width(), 160.0);
397 QCOMPARE(loader->height(), 45.0);
402 void tst_QQuickLoader::noResize()
404 QQmlComponent component(&engine, testFileUrl("/NoResize.qml"));
405 QQuickItem* item = qobject_cast<QQuickItem*>(component.create());
407 QCOMPARE(item->width(), 200.0);
408 QCOMPARE(item->height(), 80.0);
413 void tst_QQuickLoader::networkRequestUrl()
415 TestHTTPServer server(SERVER_PORT);
416 QVERIFY(server.isValid());
417 server.serveDirectory(dataDirectory());
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);
426 QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
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);
436 /* XXX Component waits until all dependencies are loaded. Is this actually possible?
437 void tst_QQuickLoader::networkComponent()
439 TestHTTPServer server(SERVER_PORT);
440 QVERIFY(server.isValid());
441 server.serveDirectory("slowdata", TestHTTPServer::Delay);
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"
448 " Component { id: comp; NW.SlowRect {} }\n"
449 " Loader { sourceComponent: comp } }")
450 , dataDirectoryUrl());
452 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
455 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::children().at(1));
457 QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
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);
468 void tst_QQuickLoader::failNetworkRequest()
470 TestHTTPServer server(SERVER_PORT);
471 QVERIFY(server.isValid());
472 server.serveDirectory(dataDirectory());
474 QTest::ignoreMessage(QtWarningMsg, "http://127.0.0.1:14450/IDontExist.qml: File not found");
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);
481 QTRY_VERIFY(loader->status() == QQuickLoader::Error);
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);
491 void tst_QQuickLoader::active()
493 // check that the item isn't instantiated until active is set to true
495 QQmlComponent component(&engine, testFileUrl("active.1.qml"));
496 QObject *object = component.create();
497 QVERIFY(object != 0);
498 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
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);
512 // check that the status is Null if active is set to false
514 QQmlComponent component(&engine, testFileUrl("active.2.qml"));
515 QObject *object = component.create();
516 QVERIFY(object != 0);
517 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
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));
529 // check that the source is not cleared if active is set to false
531 QQmlComponent component(&engine, testFileUrl("active.3.qml"));
532 QObject *object = component.create();
533 QVERIFY(object != 0);
534 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
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);
546 // check that the sourceComponent is not cleared if active is set to false
548 QQmlComponent component(&engine, testFileUrl("active.4.qml"));
549 QObject *object = component.create();
550 QVERIFY(object != 0);
551 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
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);
563 // check that the item is released if active is set to false
565 QQmlComponent component(&engine, testFileUrl("active.5.qml"));
566 QObject *object = component.create();
567 QVERIFY(object != 0);
568 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
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));
580 // check that the activeChanged signal is emitted correctly
582 QQmlComponent component(&engine, testFileUrl("active.6.qml"));
583 QObject *object = component.create();
584 QVERIFY(object != 0);
585 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
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);
610 // check that the component isn't loaded until active is set to true
612 QQmlComponent component(&engine, testFileUrl("active.7.qml"));
613 QObject *object = component.create();
614 QVERIFY(object != 0);
615 QCOMPARE(object->property("success").toBool(), true);
619 // check that the component is loaded if active is not set (true by default)
621 QQmlComponent component(&engine, testFileUrl("active.8.qml"));
622 QObject *object = component.create();
623 QVERIFY(object != 0);
624 QCOMPARE(object->property("success").toBool(), true);
629 void tst_QQuickLoader::initialPropertyValues_data()
631 QTest::addColumn<QUrl>("qmlFile");
632 QTest::addColumn<QStringList>("expectedWarnings");
633 QTest::addColumn<QStringList>("propertyNames");
634 QTest::addColumn<QVariantList>("propertyValues");
636 QTest::newRow("source url with value set in onLoaded, initially active = true") << testFileUrl("initialPropertyValues.1.qml")
638 << (QStringList() << "initialValue" << "behaviorCount")
639 << (QVariantList() << 1 << 1);
641 QTest::newRow("set source with initial property values specified, active = true") << testFileUrl("initialPropertyValues.2.qml")
643 << (QStringList() << "initialValue" << "behaviorCount")
644 << (QVariantList() << 2 << 0);
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")))
651 QTest::newRow("set source with initial property values specified, active = false, with active set true later") << testFileUrl("initialPropertyValues.4.qml")
653 << (QStringList() << "initialValue" << "behaviorCount")
654 << (QVariantList() << 4 << 0);
656 QTest::newRow("set source without initial property values specified, active = true") << testFileUrl("initialPropertyValues.5.qml")
658 << (QStringList() << "initialValue" << "behaviorCount")
659 << (QVariantList() << 0 << 0);
661 QTest::newRow("set source with initial property values specified with binding, active = true") << testFileUrl("initialPropertyValues.6.qml")
663 << (QStringList() << "initialValue" << "behaviorCount")
664 << (QVariantList() << 6 << 0);
666 QTest::newRow("ensure initial property value semantics mimic createObject") << testFileUrl("initialPropertyValues.7.qml")
668 << (QStringList() << "loaderValue" << "createObjectValue")
669 << (QVariantList() << 1 << 1);
671 QTest::newRow("ensure initial property values aren't disposed prior to component completion") << testFileUrl("initialPropertyValues.8.qml")
673 << (QStringList() << "initialValue")
674 << (QVariantList() << 6);
677 void tst_QQuickLoader::initialPropertyValues()
679 QFETCH(QUrl, qmlFile);
680 QFETCH(QStringList, expectedWarnings);
681 QFETCH(QStringList, propertyNames);
682 QFETCH(QVariantList, propertyValues);
684 TestHTTPServer server(SERVER_PORT);
685 QVERIFY(server.isValid());
686 server.serveDirectory(dataDirectory());
688 foreach (const QString &warning, expectedWarnings)
689 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
691 QQmlComponent component(&engine, qmlFile);
692 QObject *object = component.create();
693 QVERIFY(object != 0);
694 qApp->processEvents();
697 for (int i = 0; i < propertyNames.size(); ++i)
698 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
703 void tst_QQuickLoader::initialPropertyValuesBinding()
705 QQmlComponent component(&engine, testFileUrl("initialPropertyValues.binding.qml"));
706 QObject *object = component.create();
707 QVERIFY(object != 0);
709 QVERIFY(object->setProperty("bindable", QVariant(8)));
710 QCOMPARE(object->property("canaryValue").toInt(), 8);
715 void tst_QQuickLoader::initialPropertyValuesError_data()
717 QTest::addColumn<QUrl>("qmlFile");
718 QTest::addColumn<QStringList>("expectedWarnings");
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"));
723 QTest::newRow("nonexistent source url") << testFileUrl("initialPropertyValues.error.2.qml")
724 << (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": File not found"));
726 QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml")
727 << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
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"));
734 void tst_QQuickLoader::initialPropertyValuesError()
736 QFETCH(QUrl, qmlFile);
737 QFETCH(QStringList, expectedWarnings);
739 foreach (const QString &warning, expectedWarnings)
740 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
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);
752 void tst_QQuickLoader::deleteComponentCrash()
754 QQmlComponent component(&engine, testFileUrl("crash.qml"));
755 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
758 item->metaObject()->invokeMethod(item, "setLoaderSource");
760 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
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"));
774 void tst_QQuickLoader::nonItem()
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.";
779 QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
780 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
782 QVERIFY(loader->item() == 0);
787 void tst_QQuickLoader::vmeErrors()
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());
794 QVERIFY(loader->item() == 0);
800 void tst_QQuickLoader::creationContext()
802 QQmlComponent component(&engine, testFileUrl("creationContext.qml"));
804 QObject *o = component.create();
807 QCOMPARE(o->property("test").toBool(), true);
812 void tst_QQuickLoader::QTBUG_16928()
814 QQmlComponent component(&engine, testFileUrl("QTBUG_16928.qml"));
815 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
818 QCOMPARE(item->width(), 250.);
819 QCOMPARE(item->height(), 250.);
824 void tst_QQuickLoader::implicitSize()
826 QQmlComponent component(&engine, testFileUrl("implicitSize.qml"));
827 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
830 QCOMPARE(item->width(), 150.);
831 QCOMPARE(item->height(), 150.);
833 QCOMPARE(item->property("implHeight").toReal(), 100.);
834 QCOMPARE(item->property("implWidth").toReal(), 100.);
839 void tst_QQuickLoader::QTBUG_17114()
841 QQmlComponent component(&engine, testFileUrl("QTBUG_17114.qml"));
842 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
845 QCOMPARE(item->property("loaderWidth").toReal(), 32.);
846 QCOMPARE(item->property("loaderHeight").toReal(), 32.);
851 void tst_QQuickLoader::asynchronous_data()
853 QTest::addColumn<QUrl>("qmlFile");
854 QTest::addColumn<QStringList>("expectedWarnings");
856 QTest::newRow("Valid component") << testFileUrl("BigComponent.qml")
859 QTest::newRow("Non-existant component") << testFileUrl("IDoNotExist.qml")
860 << (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": File not found"));
862 QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml")
863 << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
866 void tst_QQuickLoader::asynchronous()
868 QFETCH(QUrl, qmlFile);
869 QFETCH(QStringList, expectedWarnings);
871 if (!engine.incubationController())
872 engine.setIncubationController(new PeriodicIncubationController);
873 QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
874 QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
877 QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
880 foreach (const QString &warning, expectedWarnings)
881 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
883 QVERIFY(!loader->item());
884 root->setProperty("comp", qmlFile.toString());
885 QMetaObject::invokeMethod(root, "loadComponent");
886 QVERIFY(!loader->item());
888 if (expectedWarnings.isEmpty()) {
889 QCOMPARE(loader->status(), QQuickLoader::Loading);
890 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
892 QTRY_VERIFY(loader->item());
893 QCOMPARE(loader->progress(), 1.0);
894 QCOMPARE(loader->status(), QQuickLoader::Ready);
896 QCOMPARE(loader->progress(), 1.0);
897 QTRY_COMPARE(loader->status(), QQuickLoader::Error);
903 void tst_QQuickLoader::asynchronous_clear()
905 if (!engine.incubationController())
906 engine.setIncubationController(new PeriodicIncubationController);
907 QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
908 QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
911 QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
914 QVERIFY(!loader->item());
915 root->setProperty("comp", "BigComponent.qml");
916 QMetaObject::invokeMethod(root, "loadComponent");
917 QVERIFY(!loader->item());
919 QCOMPARE(loader->status(), QQuickLoader::Loading);
920 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
922 // clear before component created
923 root->setProperty("comp", "");
924 QMetaObject::invokeMethod(root, "loadComponent");
925 QVERIFY(!loader->item());
926 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 0);
928 QCOMPARE(loader->progress(), 0.0);
929 QCOMPARE(loader->status(), QQuickLoader::Null);
930 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
932 // check loading component
933 root->setProperty("comp", "Rect120x60.qml");
934 QMetaObject::invokeMethod(root, "loadComponent");
935 QVERIFY(!loader->item());
937 QCOMPARE(loader->status(), QQuickLoader::Loading);
938 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
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);
946 void tst_QQuickLoader::parented()
948 QQmlComponent component(&engine, testFileUrl("parented.qml"));
949 QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
952 QQuickItem *item = root->findChild<QQuickItem*>("comp");
955 QVERIFY(item->parentItem() == root);
957 QCOMPARE(item->width(), 300.);
958 QCOMPARE(item->height(), 300.);
963 void tst_QQuickLoader::sizeBound()
965 QQmlComponent component(&engine, testFileUrl("sizebound.qml"));
966 QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
968 QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
969 QVERIFY(loader != 0);
971 QVERIFY(loader->item());
973 QCOMPARE(loader->width(), 50.0);
974 QCOMPARE(loader->height(), 60.0);
976 QMetaObject::invokeMethod(root, "switchComponent");
978 QCOMPARE(loader->width(), 80.0);
979 QCOMPARE(loader->height(), 90.0);
985 QTEST_MAIN(tst_QQuickLoader)
987 #include "tst_qquickloader.moc"