1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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/qquickloader_p.h>
49 #include "testhttpserver.h"
50 #include "../../shared/util.h"
52 #define SERVER_PORT 14450
54 class PeriodicIncubationController : public QObject,
55 public QDeclarativeIncubationController
58 PeriodicIncubationController() {
63 virtual void timerEvent(QTimerEvent *) {
68 class tst_QQuickLoader : public QDeclarativeDataTest
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();
109 QDeclarativeEngine engine;
113 tst_QQuickLoader::tst_QQuickLoader()
117 void tst_QQuickLoader::sourceOrComponent()
119 QFETCH(QString, sourceOrComponent);
120 QFETCH(QString, sourceDefinition);
121 QFETCH(QUrl, sourceUrl);
122 QFETCH(QString, errorString);
124 bool error = !errorString.isEmpty();
126 QTest::ignoreMessage(QtWarningMsg, errorString.toUtf8().constData());
128 QDeclarativeComponent component(&engine);
129 component.setData(QByteArray(
130 "import QtQuick 2.0\n"
132 " property int onItemChangedCount: 0\n"
133 " property int onSourceChangedCount: 0\n"
134 " property int onSourceComponentChangedCount: 0\n"
135 " property int onStatusChangedCount: 0\n"
136 " property int onProgressChangedCount: 0\n"
137 " property int onLoadedCount: 0\n")
138 + sourceDefinition.toUtf8()
140 " onItemChanged: onItemChangedCount += 1\n"
141 " onSourceChanged: onSourceChangedCount += 1\n"
142 " onSourceComponentChanged: onSourceComponentChangedCount += 1\n"
143 " onStatusChanged: onStatusChangedCount += 1\n"
144 " onProgressChanged: onProgressChangedCount += 1\n"
145 " onLoaded: onLoadedCount += 1\n"
147 , dataDirectoryUrl());
149 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
150 QVERIFY(loader != 0);
151 QCOMPARE(loader->item() == 0, error);
152 QCOMPARE(loader->source(), sourceUrl);
153 QCOMPARE(loader->progress(), 1.0);
155 QCOMPARE(loader->status(), error ? QQuickLoader::Error : QQuickLoader::Ready);
156 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), error ? 0: 1);
159 bool sourceComponentIsChildOfLoader = false;
160 for (int ii = 0; ii < loader->children().size(); ++ii) {
161 QDeclarativeComponent *c = qobject_cast<QDeclarativeComponent*>(loader->children().at(ii));
162 if (c && c == loader->sourceComponent()) {
163 sourceComponentIsChildOfLoader = true;
166 QVERIFY(sourceComponentIsChildOfLoader);
169 if (sourceOrComponent == "component") {
170 QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 1);
171 QCOMPARE(loader->property("onSourceChangedCount").toInt(), 0);
173 QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 0);
174 QCOMPARE(loader->property("onSourceChangedCount").toInt(), 1);
176 QCOMPARE(loader->property("onStatusChangedCount").toInt(), 1);
177 QCOMPARE(loader->property("onProgressChangedCount").toInt(), 1);
179 QCOMPARE(loader->property("onItemChangedCount").toInt(), error ? 0 : 1);
180 QCOMPARE(loader->property("onLoadedCount").toInt(), error ? 0 : 1);
185 void tst_QQuickLoader::sourceOrComponent_data()
187 QTest::addColumn<QString>("sourceOrComponent");
188 QTest::addColumn<QString>("sourceDefinition");
189 QTest::addColumn<QUrl>("sourceUrl");
190 QTest::addColumn<QString>("errorString");
192 QTest::newRow("source") << "source" << "source: 'Rect120x60.qml'\n" << testFileUrl("Rect120x60.qml") << "";
193 QTest::newRow("sourceComponent") << "component" << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
194 QTest::newRow("invalid source") << "source" << "source: 'IDontExist.qml'\n" << testFileUrl("IDontExist.qml")
195 << QString(testFileUrl("IDontExist.qml").toString() + ": File not found");
198 void tst_QQuickLoader::clear()
201 QDeclarativeComponent component(&engine);
202 component.setData(QByteArray(
203 "import QtQuick 2.0\n"
204 " Loader { id: loader\n"
205 " source: 'Rect120x60.qml'\n"
206 " Timer { interval: 200; running: true; onTriggered: loader.source = '' }\n"
208 , dataDirectoryUrl());
209 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
210 QVERIFY(loader != 0);
211 QVERIFY(loader->item());
212 QCOMPARE(loader->progress(), 1.0);
213 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
215 QTRY_VERIFY(loader->item() == 0);
216 QCOMPARE(loader->progress(), 0.0);
217 QCOMPARE(loader->status(), QQuickLoader::Null);
218 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
223 QDeclarativeComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
224 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
227 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
229 QVERIFY(loader->item());
230 QCOMPARE(loader->progress(), 1.0);
231 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
233 loader->setSourceComponent(0);
235 QVERIFY(loader->item() == 0);
236 QCOMPARE(loader->progress(), 0.0);
237 QCOMPARE(loader->status(), QQuickLoader::Null);
238 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
243 QDeclarativeComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
244 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
247 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
249 QVERIFY(loader->item());
250 QCOMPARE(loader->progress(), 1.0);
251 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
253 QMetaObject::invokeMethod(item, "clear");
255 QVERIFY(loader->item() == 0);
256 QCOMPARE(loader->progress(), 0.0);
257 QCOMPARE(loader->status(), QQuickLoader::Null);
258 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
264 void tst_QQuickLoader::urlToComponent()
266 QDeclarativeComponent component(&engine);
267 component.setData(QByteArray("import QtQuick 2.0\n"
270 " Component { id: myComp; Rectangle { width: 10; height: 10 } }\n"
271 " source: \"Rect120x60.qml\"\n"
272 " Timer { interval: 100; running: true; onTriggered: loader.sourceComponent = myComp }\n"
274 , dataDirectoryUrl());
275 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
277 QTRY_VERIFY(loader != 0);
278 QVERIFY(loader->item());
279 QCOMPARE(loader->progress(), 1.0);
280 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
281 QCOMPARE(loader->width(), 10.0);
282 QCOMPARE(loader->height(), 10.0);
287 void tst_QQuickLoader::componentToUrl()
289 QDeclarativeComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
290 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
293 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
295 QVERIFY(loader->item());
296 QCOMPARE(loader->progress(), 1.0);
297 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
299 loader->setSource(testFileUrl("/Rect120x60.qml"));
300 QVERIFY(loader->item());
301 QCOMPARE(loader->progress(), 1.0);
302 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
303 QCOMPARE(loader->width(), 120.0);
304 QCOMPARE(loader->height(), 60.0);
309 void tst_QQuickLoader::anchoredLoader()
311 QDeclarativeComponent component(&engine, testFileUrl("/AnchoredLoader.qml"));
312 QQuickItem *rootItem = qobject_cast<QQuickItem*>(component.create());
313 QVERIFY(rootItem != 0);
314 QQuickItem *loader = rootItem->findChild<QQuickItem*>("loader");
315 QQuickItem *sourceElement = rootItem->findChild<QQuickItem*>("sourceElement");
317 QVERIFY(loader != 0);
318 QVERIFY(sourceElement != 0);
320 QCOMPARE(rootItem->width(), 300.0);
321 QCOMPARE(rootItem->height(), 200.0);
323 QCOMPARE(loader->width(), 300.0);
324 QCOMPARE(loader->height(), 200.0);
326 QCOMPARE(sourceElement->width(), 300.0);
327 QCOMPARE(sourceElement->height(), 200.0);
330 void tst_QQuickLoader::sizeLoaderToItem()
332 QDeclarativeComponent component(&engine, testFileUrl("/SizeToItem.qml"));
333 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
334 QVERIFY(loader != 0);
335 QCOMPARE(loader->width(), 120.0);
336 QCOMPARE(loader->height(), 60.0);
339 QQuickItem *rect = qobject_cast<QQuickItem*>(loader->item());
343 QCOMPARE(loader->width(), 150.0);
344 QCOMPARE(loader->height(), 45.0);
346 // Check explicit width
347 loader->setWidth(200.0);
348 QCOMPARE(loader->width(), 200.0);
349 QCOMPARE(rect->width(), 200.0);
350 rect->setWidth(100.0); // when rect changes ...
351 QCOMPARE(rect->width(), 100.0); // ... it changes
352 QCOMPARE(loader->width(), 200.0); // ... but loader stays the same
354 // Check explicit height
355 loader->setHeight(200.0);
356 QCOMPARE(loader->height(), 200.0);
357 QCOMPARE(rect->height(), 200.0);
358 rect->setHeight(100.0); // when rect changes ...
359 QCOMPARE(rect->height(), 100.0); // ... it changes
360 QCOMPARE(loader->height(), 200.0); // ... but loader stays the same
363 loader->setWidth(180);
364 loader->setHeight(30);
365 QCOMPARE(rect->width(), 180.0);
366 QCOMPARE(rect->height(), 30.0);
371 void tst_QQuickLoader::sizeItemToLoader()
373 QDeclarativeComponent component(&engine, testFileUrl("/SizeToLoader.qml"));
374 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
375 QVERIFY(loader != 0);
376 QCOMPARE(loader->width(), 200.0);
377 QCOMPARE(loader->height(), 80.0);
379 QQuickItem *rect = qobject_cast<QQuickItem*>(loader->item());
381 QCOMPARE(rect->width(), 200.0);
382 QCOMPARE(rect->height(), 80.0);
385 loader->setWidth(180);
386 loader->setHeight(30);
387 QCOMPARE(rect->width(), 180.0);
388 QCOMPARE(rect->height(), 30.0);
391 loader->resetWidth(); // reset explicit size
392 loader->resetHeight();
395 QCOMPARE(loader->width(), 160.0);
396 QCOMPARE(loader->height(), 45.0);
401 void tst_QQuickLoader::noResize()
403 QDeclarativeComponent component(&engine, testFileUrl("/NoResize.qml"));
404 QQuickItem* item = qobject_cast<QQuickItem*>(component.create());
406 QCOMPARE(item->width(), 200.0);
407 QCOMPARE(item->height(), 80.0);
412 void tst_QQuickLoader::networkRequestUrl()
414 TestHTTPServer server(SERVER_PORT);
415 QVERIFY(server.isValid());
416 server.serveDirectory(dataDirectory());
418 QDeclarativeComponent component(&engine);
419 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"));
420 if (component.isError())
421 qDebug() << component.errors();
422 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
423 QVERIFY(loader != 0);
425 QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
427 QVERIFY(loader->item());
428 QCOMPARE(loader->progress(), 1.0);
429 QCOMPARE(loader->property("signalCount").toInt(), 1);
430 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
435 /* XXX Component waits until all dependencies are loaded. Is this actually possible?
436 void tst_QQuickLoader::networkComponent()
438 TestHTTPServer server(SERVER_PORT);
439 QVERIFY(server.isValid());
440 server.serveDirectory("slowdata", TestHTTPServer::Delay);
442 QDeclarativeComponent component(&engine);
443 component.setData(QByteArray(
444 "import QtQuick 2.0\n"
445 "import \"http://127.0.0.1:14450/\" as NW\n"
447 " Component { id: comp; NW.SlowRect {} }\n"
448 " Loader { sourceComponent: comp } }")
449 , dataDirectoryUrl());
451 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
454 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::children().at(1));
456 QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
458 QVERIFY(loader->item());
459 QCOMPARE(loader->progress(), 1.0);
460 QCOMPARE(loader->status(), QQuickLoader::Ready);
461 QCOMPARE(static_cast<QQuickItem*>(loader)->children().count(), 1);
467 void tst_QQuickLoader::failNetworkRequest()
469 TestHTTPServer server(SERVER_PORT);
470 QVERIFY(server.isValid());
471 server.serveDirectory(dataDirectory());
473 QTest::ignoreMessage(QtWarningMsg, "http://127.0.0.1:14450/IDontExist.qml: File not found");
475 QDeclarativeComponent component(&engine);
476 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"));
477 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
478 QVERIFY(loader != 0);
480 QTRY_VERIFY(loader->status() == QQuickLoader::Error);
482 QVERIFY(loader->item() == 0);
483 QCOMPARE(loader->progress(), 0.0);
484 QCOMPARE(loader->property("did_load").toInt(), 123);
485 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
490 void tst_QQuickLoader::active()
492 // check that the item isn't instantiated until active is set to true
494 QDeclarativeComponent component(&engine, testFileUrl("active.1.qml"));
495 QObject *object = component.create();
496 QVERIFY(object != 0);
497 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
499 QVERIFY(loader->active() == false); // set manually to false
500 QVERIFY(loader->item() == 0);
501 QMetaObject::invokeMethod(object, "doSetSourceComponent");
502 QVERIFY(loader->item() == 0);
503 QMetaObject::invokeMethod(object, "doSetSource");
504 QVERIFY(loader->item() == 0);
505 QMetaObject::invokeMethod(object, "doSetActive");
506 QVERIFY(loader->item() != 0);
511 // check that the status is Null if active is set to false
513 QDeclarativeComponent component(&engine, testFileUrl("active.2.qml"));
514 QObject *object = component.create();
515 QVERIFY(object != 0);
516 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
518 QVERIFY(loader->active() == true); // active is true by default
519 QCOMPARE(loader->status(), QQuickLoader::Ready);
520 int currStatusChangedCount = loader->property("statusChangedCount").toInt();
521 QMetaObject::invokeMethod(object, "doSetInactive");
522 QCOMPARE(loader->status(), QQuickLoader::Null);
523 QCOMPARE(loader->property("statusChangedCount").toInt(), (currStatusChangedCount+1));
528 // check that the source is not cleared if active is set to false
530 QDeclarativeComponent component(&engine, testFileUrl("active.3.qml"));
531 QObject *object = component.create();
532 QVERIFY(object != 0);
533 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
535 QVERIFY(loader->active() == true); // active is true by default
536 QVERIFY(!loader->source().isEmpty());
537 int currSourceChangedCount = loader->property("sourceChangedCount").toInt();
538 QMetaObject::invokeMethod(object, "doSetInactive");
539 QVERIFY(!loader->source().isEmpty());
540 QCOMPARE(loader->property("sourceChangedCount").toInt(), currSourceChangedCount);
545 // check that the sourceComponent is not cleared if active is set to false
547 QDeclarativeComponent component(&engine, testFileUrl("active.4.qml"));
548 QObject *object = component.create();
549 QVERIFY(object != 0);
550 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
552 QVERIFY(loader->active() == true); // active is true by default
553 QVERIFY(loader->sourceComponent() != 0);
554 int currSourceComponentChangedCount = loader->property("sourceComponentChangedCount").toInt();
555 QMetaObject::invokeMethod(object, "doSetInactive");
556 QVERIFY(loader->sourceComponent() != 0);
557 QCOMPARE(loader->property("sourceComponentChangedCount").toInt(), currSourceComponentChangedCount);
562 // check that the item is released if active is set to false
564 QDeclarativeComponent component(&engine, testFileUrl("active.5.qml"));
565 QObject *object = component.create();
566 QVERIFY(object != 0);
567 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
569 QVERIFY(loader->active() == true); // active is true by default
570 QVERIFY(loader->item() != 0);
571 int currItemChangedCount = loader->property("itemChangedCount").toInt();
572 QMetaObject::invokeMethod(object, "doSetInactive");
573 QVERIFY(loader->item() == 0);
574 QCOMPARE(loader->property("itemChangedCount").toInt(), (currItemChangedCount+1));
579 // check that the activeChanged signal is emitted correctly
581 QDeclarativeComponent component(&engine, testFileUrl("active.6.qml"));
582 QObject *object = component.create();
583 QVERIFY(object != 0);
584 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
586 QVERIFY(loader->active() == true); // active is true by default
587 loader->setActive(true); // no effect
588 QCOMPARE(loader->property("activeChangedCount").toInt(), 0);
589 loader->setActive(false); // change signal should be emitted
590 QCOMPARE(loader->property("activeChangedCount").toInt(), 1);
591 loader->setActive(false); // no effect
592 QCOMPARE(loader->property("activeChangedCount").toInt(), 1);
593 loader->setActive(true); // change signal should be emitted
594 QCOMPARE(loader->property("activeChangedCount").toInt(), 2);
595 loader->setActive(false); // change signal should be emitted
596 QCOMPARE(loader->property("activeChangedCount").toInt(), 3);
597 QMetaObject::invokeMethod(object, "doSetActive");
598 QCOMPARE(loader->property("activeChangedCount").toInt(), 4);
599 QMetaObject::invokeMethod(object, "doSetActive");
600 QCOMPARE(loader->property("activeChangedCount").toInt(), 4);
601 QMetaObject::invokeMethod(object, "doSetInactive");
602 QCOMPARE(loader->property("activeChangedCount").toInt(), 5);
603 loader->setActive(true); // change signal should be emitted
604 QCOMPARE(loader->property("activeChangedCount").toInt(), 6);
609 // check that the component isn't loaded until active is set to true
611 QDeclarativeComponent component(&engine, testFileUrl("active.7.qml"));
612 QObject *object = component.create();
613 QVERIFY(object != 0);
614 QCOMPARE(object->property("success").toBool(), true);
618 // check that the component is loaded if active is not set (true by default)
620 QDeclarativeComponent component(&engine, testFileUrl("active.8.qml"));
621 QObject *object = component.create();
622 QVERIFY(object != 0);
623 QCOMPARE(object->property("success").toBool(), true);
628 void tst_QQuickLoader::initialPropertyValues_data()
630 QTest::addColumn<QUrl>("qmlFile");
631 QTest::addColumn<QStringList>("expectedWarnings");
632 QTest::addColumn<QStringList>("propertyNames");
633 QTest::addColumn<QVariantList>("propertyValues");
635 QTest::newRow("source url with value set in onLoaded, initially active = true") << testFileUrl("initialPropertyValues.1.qml")
637 << (QStringList() << "initialValue" << "behaviorCount")
638 << (QVariantList() << 1 << 1);
640 QTest::newRow("set source with initial property values specified, active = true") << testFileUrl("initialPropertyValues.2.qml")
642 << (QStringList() << "initialValue" << "behaviorCount")
643 << (QVariantList() << 2 << 0);
645 QTest::newRow("set source with initial property values specified, active = false") << testFileUrl("initialPropertyValues.3.qml")
646 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("initialPropertyValues.3.qml").toLocalFile() + QLatin1String(":16: TypeError: Cannot read property 'canary' of null")))
650 QTest::newRow("set source with initial property values specified, active = false, with active set true later") << testFileUrl("initialPropertyValues.4.qml")
652 << (QStringList() << "initialValue" << "behaviorCount")
653 << (QVariantList() << 4 << 0);
655 QTest::newRow("set source without initial property values specified, active = true") << testFileUrl("initialPropertyValues.5.qml")
657 << (QStringList() << "initialValue" << "behaviorCount")
658 << (QVariantList() << 0 << 0);
660 QTest::newRow("set source with initial property values specified with binding, active = true") << testFileUrl("initialPropertyValues.6.qml")
662 << (QStringList() << "initialValue" << "behaviorCount")
663 << (QVariantList() << 6 << 0);
665 QTest::newRow("ensure initial property value semantics mimic createObject") << testFileUrl("initialPropertyValues.7.qml")
667 << (QStringList() << "loaderValue" << "createObjectValue")
668 << (QVariantList() << 1 << 1);
670 QTest::newRow("ensure initial property values aren't disposed prior to component completion") << testFileUrl("initialPropertyValues.8.qml")
672 << (QStringList() << "initialValue")
673 << (QVariantList() << 6);
676 void tst_QQuickLoader::initialPropertyValues()
678 QFETCH(QUrl, qmlFile);
679 QFETCH(QStringList, expectedWarnings);
680 QFETCH(QStringList, propertyNames);
681 QFETCH(QVariantList, propertyValues);
683 TestHTTPServer server(SERVER_PORT);
684 QVERIFY(server.isValid());
685 server.serveDirectory(dataDirectory());
687 foreach (const QString &warning, expectedWarnings)
688 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
690 QDeclarativeComponent component(&engine, qmlFile);
691 QObject *object = component.create();
692 QVERIFY(object != 0);
693 qApp->processEvents();
696 for (int i = 0; i < propertyNames.size(); ++i)
697 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
702 void tst_QQuickLoader::initialPropertyValuesBinding()
704 QDeclarativeComponent component(&engine, testFileUrl("initialPropertyValues.binding.qml"));
705 QObject *object = component.create();
706 QVERIFY(object != 0);
708 QVERIFY(object->setProperty("bindable", QVariant(8)));
709 QCOMPARE(object->property("canaryValue").toInt(), 8);
714 void tst_QQuickLoader::initialPropertyValuesError_data()
716 QTest::addColumn<QUrl>("qmlFile");
717 QTest::addColumn<QStringList>("expectedWarnings");
719 QTest::newRow("invalid initial property values object") << testFileUrl("initialPropertyValues.error.1.qml")
720 << (QStringList() << QString(testFileUrl("initialPropertyValues.error.1.qml").toString() + ":6:5: QML Loader: setSource: value is not an object"));
722 QTest::newRow("nonexistent source url") << testFileUrl("initialPropertyValues.error.2.qml")
723 << (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": File not found"));
725 QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml")
726 << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
728 QTest::newRow("invalid initial property values object with invalid property access") << testFileUrl("initialPropertyValues.error.4.qml")
729 << (QStringList() << QString(testFileUrl("initialPropertyValues.error.4.qml").toString() + ":7:5: QML Loader: setSource: value is not an object")
730 << QString(testFileUrl("initialPropertyValues.error.4.qml").toString() + ":5: TypeError: Cannot read property 'canary' of null"));
733 void tst_QQuickLoader::initialPropertyValuesError()
735 QFETCH(QUrl, qmlFile);
736 QFETCH(QStringList, expectedWarnings);
738 foreach (const QString &warning, expectedWarnings)
739 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
741 QDeclarativeComponent component(&engine, qmlFile);
742 QObject *object = component.create();
743 QVERIFY(object != 0);
744 QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
745 QVERIFY(loader != 0);
746 QVERIFY(loader->item() == 0);
751 void tst_QQuickLoader::deleteComponentCrash()
753 QDeclarativeComponent component(&engine, testFileUrl("crash.qml"));
754 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
757 item->metaObject()->invokeMethod(item, "setLoaderSource");
759 QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
761 QVERIFY(loader->item());
762 QCOMPARE(loader->item()->objectName(), QLatin1String("blue"));
763 QCOMPARE(loader->progress(), 1.0);
764 QCOMPARE(loader->status(), QQuickLoader::Ready);
765 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
766 QCoreApplication::processEvents();
767 QTRY_COMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
768 QVERIFY(loader->source() == testFileUrl("BlueRect.qml"));
773 void tst_QQuickLoader::nonItem()
775 QDeclarativeComponent component(&engine, testFileUrl("nonItem.qml"));
776 QString err = testFileUrl("nonItem.qml").toString() + ":3:1: QML Loader: Loader does not support loading non-visual elements.";
778 QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
779 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
781 QVERIFY(loader->item() == 0);
786 void tst_QQuickLoader::vmeErrors()
788 QDeclarativeComponent component(&engine, testFileUrl("vmeErrors.qml"));
789 QString err = testFileUrl("VmeError.qml").toString() + ":6: Cannot assign object type QObject with no default method";
790 QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
791 QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
793 QVERIFY(loader->item() == 0);
799 void tst_QQuickLoader::creationContext()
801 QDeclarativeComponent component(&engine, testFileUrl("creationContext.qml"));
803 QObject *o = component.create();
806 QCOMPARE(o->property("test").toBool(), true);
811 void tst_QQuickLoader::QTBUG_16928()
813 QDeclarativeComponent component(&engine, testFileUrl("QTBUG_16928.qml"));
814 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
817 QCOMPARE(item->width(), 250.);
818 QCOMPARE(item->height(), 250.);
823 void tst_QQuickLoader::implicitSize()
825 QDeclarativeComponent component(&engine, testFileUrl("implicitSize.qml"));
826 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
829 QCOMPARE(item->width(), 150.);
830 QCOMPARE(item->height(), 150.);
832 QCOMPARE(item->property("implHeight").toReal(), 100.);
833 QCOMPARE(item->property("implWidth").toReal(), 100.);
838 void tst_QQuickLoader::QTBUG_17114()
840 QDeclarativeComponent component(&engine, testFileUrl("QTBUG_17114.qml"));
841 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
844 QCOMPARE(item->property("loaderWidth").toReal(), 32.);
845 QCOMPARE(item->property("loaderHeight").toReal(), 32.);
850 void tst_QQuickLoader::asynchronous_data()
852 QTest::addColumn<QUrl>("qmlFile");
853 QTest::addColumn<QStringList>("expectedWarnings");
855 QTest::newRow("Valid component") << testFileUrl("BigComponent.qml")
858 QTest::newRow("Non-existant component") << testFileUrl("IDoNotExist.qml")
859 << (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": File not found"));
861 QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml")
862 << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
865 void tst_QQuickLoader::asynchronous()
867 QFETCH(QUrl, qmlFile);
868 QFETCH(QStringList, expectedWarnings);
870 if (!engine.incubationController())
871 engine.setIncubationController(new PeriodicIncubationController);
872 QDeclarativeComponent component(&engine, testFileUrl("asynchronous.qml"));
873 QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
876 QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
879 foreach (const QString &warning, expectedWarnings)
880 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
882 QVERIFY(!loader->item());
883 root->setProperty("comp", qmlFile.toString());
884 QMetaObject::invokeMethod(root, "loadComponent");
885 QVERIFY(!loader->item());
887 if (expectedWarnings.isEmpty()) {
888 QCOMPARE(loader->status(), QQuickLoader::Loading);
889 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
891 QTRY_VERIFY(loader->item());
892 QCOMPARE(loader->progress(), 1.0);
893 QCOMPARE(loader->status(), QQuickLoader::Ready);
895 QCOMPARE(loader->progress(), 1.0);
896 QTRY_COMPARE(loader->status(), QQuickLoader::Error);
902 void tst_QQuickLoader::asynchronous_clear()
904 if (!engine.incubationController())
905 engine.setIncubationController(new PeriodicIncubationController);
906 QDeclarativeComponent component(&engine, testFileUrl("asynchronous.qml"));
907 QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
910 QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
913 QVERIFY(!loader->item());
914 root->setProperty("comp", "BigComponent.qml");
915 QMetaObject::invokeMethod(root, "loadComponent");
916 QVERIFY(!loader->item());
918 QCOMPARE(loader->status(), QQuickLoader::Loading);
919 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
921 // clear before component created
922 root->setProperty("comp", "");
923 QMetaObject::invokeMethod(root, "loadComponent");
924 QVERIFY(!loader->item());
925 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 0);
927 QCOMPARE(loader->progress(), 0.0);
928 QCOMPARE(loader->status(), QQuickLoader::Null);
929 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
931 // check loading component
932 root->setProperty("comp", "Rect120x60.qml");
933 QMetaObject::invokeMethod(root, "loadComponent");
934 QVERIFY(!loader->item());
936 QCOMPARE(loader->status(), QQuickLoader::Loading);
937 QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
939 QTRY_VERIFY(loader->item());
940 QCOMPARE(loader->progress(), 1.0);
941 QCOMPARE(loader->status(), QQuickLoader::Ready);
942 QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
945 void tst_QQuickLoader::parented()
947 QDeclarativeComponent component(&engine, testFileUrl("parented.qml"));
948 QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
951 QQuickItem *item = root->findChild<QQuickItem*>("comp");
954 QVERIFY(item->parentItem() == root);
956 QCOMPARE(item->width(), 300.);
957 QCOMPARE(item->height(), 300.);
963 QTEST_MAIN(tst_QQuickLoader)
965 #include "tst_qquickloader.moc"