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() {
66
virtual void timerEvent(QTimerEvent *) {
70
virtual void incubatingObjectCountChanged(int count) {
76
class tst_QQuickLoader : public QQmlDataTest
84
void sourceOrComponent();
85
void sourceOrComponent_data();
87
void urlToComponent();
88
void componentToUrl();
89
void anchoredLoader();
90
void sizeLoaderToItem();
91
void sizeItemToLoader();
93
void networkRequestUrl();
94
void failNetworkRequest();
95
void networkComponent();
97
void initialPropertyValues_data();
98
void initialPropertyValues();
99
void initialPropertyValuesBinding();
100
void initialPropertyValuesError_data();
101
void initialPropertyValuesError();
103
void deleteComponentCrash();
106
void creationContext();
110
void asynchronous_data();
112
void asynchronous_clear();
113
void simultaneousSyncAsync();
124
tst_QQuickLoader::tst_QQuickLoader()
128
void tst_QQuickLoader::sourceOrComponent()
130
QFETCH(QString, sourceOrComponent);
131
QFETCH(QString, sourceDefinition);
132
QFETCH(QUrl, sourceUrl);
133
QFETCH(QString, errorString);
135
bool error = !errorString.isEmpty();
137
QTest::ignoreMessage(QtWarningMsg, errorString.toUtf8().constData());
139
QQmlComponent component(&engine);
140
component.setData(QByteArray(
141
"import QtQuick 2.0\n"
143
" property int onItemChangedCount: 0\n"
144
" property int onSourceChangedCount: 0\n"
145
" property int onSourceComponentChangedCount: 0\n"
146
" property int onStatusChangedCount: 0\n"
147
" property int onProgressChangedCount: 0\n"
148
" property int onLoadedCount: 0\n")
149
+ sourceDefinition.toUtf8()
151
" onItemChanged: onItemChangedCount += 1\n"
152
" onSourceChanged: onSourceChangedCount += 1\n"
153
" onSourceComponentChanged: onSourceComponentChangedCount += 1\n"
154
" onStatusChanged: onStatusChangedCount += 1\n"
155
" onProgressChanged: onProgressChangedCount += 1\n"
156
" onLoaded: onLoadedCount += 1\n"
158
, dataDirectoryUrl());
160
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
161
QVERIFY(loader != 0);
162
QCOMPARE(loader->item() == 0, error);
163
QCOMPARE(loader->source(), sourceUrl);
164
QCOMPARE(loader->progress(), 1.0);
166
QCOMPARE(loader->status(), error ? QQuickLoader::Error : QQuickLoader::Ready);
167
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), error ? 0: 1);
170
bool sourceComponentIsChildOfLoader = false;
171
for (int ii = 0; ii < loader->children().size(); ++ii) {
172
QQmlComponent *c = qobject_cast<QQmlComponent*>(loader->children().at(ii));
173
if (c && c == loader->sourceComponent()) {
174
sourceComponentIsChildOfLoader = true;
177
QVERIFY(sourceComponentIsChildOfLoader);
180
if (sourceOrComponent == "component") {
181
QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 1);
182
QCOMPARE(loader->property("onSourceChangedCount").toInt(), 0);
184
QCOMPARE(loader->property("onSourceComponentChangedCount").toInt(), 0);
185
QCOMPARE(loader->property("onSourceChangedCount").toInt(), 1);
187
QCOMPARE(loader->property("onStatusChangedCount").toInt(), 1);
188
QCOMPARE(loader->property("onProgressChangedCount").toInt(), 1);
190
QCOMPARE(loader->property("onItemChangedCount").toInt(), error ? 0 : 1);
191
QCOMPARE(loader->property("onLoadedCount").toInt(), error ? 0 : 1);
196
void tst_QQuickLoader::sourceOrComponent_data()
198
QTest::addColumn<QString>("sourceOrComponent");
199
QTest::addColumn<QString>("sourceDefinition");
200
QTest::addColumn<QUrl>("sourceUrl");
201
QTest::addColumn<QString>("errorString");
203
QTest::newRow("source") << "source" << "source: 'Rect120x60.qml'\n" << testFileUrl("Rect120x60.qml") << "";
204
QTest::newRow("sourceComponent") << "component" << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << "";
205
QTest::newRow("invalid source") << "source" << "source: 'IDontExist.qml'\n" << testFileUrl("IDontExist.qml")
206
<< QString(testFileUrl("IDontExist.qml").toString() + ": File not found");
209
void tst_QQuickLoader::clear()
212
QQmlComponent component(&engine);
213
component.setData(QByteArray(
214
"import QtQuick 2.0\n"
215
" Loader { id: loader\n"
216
" source: 'Rect120x60.qml'\n"
217
" Timer { interval: 200; running: true; onTriggered: loader.source = '' }\n"
219
, dataDirectoryUrl());
220
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
221
QVERIFY(loader != 0);
222
QVERIFY(loader->item());
223
QCOMPARE(loader->progress(), 1.0);
224
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
226
QTRY_VERIFY(loader->item() == 0);
227
QCOMPARE(loader->progress(), 0.0);
228
QCOMPARE(loader->status(), QQuickLoader::Null);
229
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
234
QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
235
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
238
QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
240
QVERIFY(loader->item());
241
QCOMPARE(loader->progress(), 1.0);
242
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
244
loader->setSourceComponent(0);
246
QVERIFY(loader->item() == 0);
247
QCOMPARE(loader->progress(), 0.0);
248
QCOMPARE(loader->status(), QQuickLoader::Null);
249
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
254
QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
255
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
258
QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
260
QVERIFY(loader->item());
261
QCOMPARE(loader->progress(), 1.0);
262
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
264
QMetaObject::invokeMethod(item, "clear");
266
QVERIFY(loader->item() == 0);
267
QCOMPARE(loader->progress(), 0.0);
268
QCOMPARE(loader->status(), QQuickLoader::Null);
269
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
275
void tst_QQuickLoader::urlToComponent()
277
QQmlComponent component(&engine);
278
component.setData(QByteArray("import QtQuick 2.0\n"
281
" Component { id: myComp; Rectangle { width: 10; height: 10 } }\n"
282
" source: \"Rect120x60.qml\"\n"
283
" Timer { interval: 100; running: true; onTriggered: loader.sourceComponent = myComp }\n"
285
, dataDirectoryUrl());
286
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
288
QTRY_VERIFY(loader != 0);
289
QVERIFY(loader->item());
290
QCOMPARE(loader->progress(), 1.0);
291
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
292
QCOMPARE(loader->width(), 10.0);
293
QCOMPARE(loader->height(), 10.0);
298
void tst_QQuickLoader::componentToUrl()
300
QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
301
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
304
QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
306
QVERIFY(loader->item());
307
QCOMPARE(loader->progress(), 1.0);
308
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
310
loader->setSource(testFileUrl("/Rect120x60.qml"));
311
QVERIFY(loader->item());
312
QCOMPARE(loader->progress(), 1.0);
313
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
314
QCOMPARE(loader->width(), 120.0);
315
QCOMPARE(loader->height(), 60.0);
320
void tst_QQuickLoader::anchoredLoader()
322
QQmlComponent component(&engine, testFileUrl("/AnchoredLoader.qml"));
323
QQuickItem *rootItem = qobject_cast<QQuickItem*>(component.create());
324
QVERIFY(rootItem != 0);
325
QQuickItem *loader = rootItem->findChild<QQuickItem*>("loader");
326
QQuickItem *sourceElement = rootItem->findChild<QQuickItem*>("sourceElement");
328
QVERIFY(loader != 0);
329
QVERIFY(sourceElement != 0);
331
QCOMPARE(rootItem->width(), 300.0);
332
QCOMPARE(rootItem->height(), 200.0);
334
QCOMPARE(loader->width(), 300.0);
335
QCOMPARE(loader->height(), 200.0);
337
QCOMPARE(sourceElement->width(), 300.0);
338
QCOMPARE(sourceElement->height(), 200.0);
341
void tst_QQuickLoader::sizeLoaderToItem()
343
QQmlComponent component(&engine, testFileUrl("/SizeToItem.qml"));
344
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
345
QVERIFY(loader != 0);
346
QCOMPARE(loader->width(), 120.0);
347
QCOMPARE(loader->height(), 60.0);
350
QQuickItem *rect = qobject_cast<QQuickItem*>(loader->item());
354
QCOMPARE(loader->width(), 150.0);
355
QCOMPARE(loader->height(), 45.0);
357
// Check explicit width
358
loader->setWidth(200.0);
359
QCOMPARE(loader->width(), 200.0);
360
QCOMPARE(rect->width(), 200.0);
361
rect->setWidth(100.0); // when rect changes ...
362
QCOMPARE(rect->width(), 100.0); // ... it changes
363
QCOMPARE(loader->width(), 200.0); // ... but loader stays the same
365
// Check explicit height
366
loader->setHeight(200.0);
367
QCOMPARE(loader->height(), 200.0);
368
QCOMPARE(rect->height(), 200.0);
369
rect->setHeight(100.0); // when rect changes ...
370
QCOMPARE(rect->height(), 100.0); // ... it changes
371
QCOMPARE(loader->height(), 200.0); // ... but loader stays the same
374
loader->setWidth(180);
375
loader->setHeight(30);
376
QCOMPARE(rect->width(), 180.0);
377
QCOMPARE(rect->height(), 30.0);
382
void tst_QQuickLoader::sizeItemToLoader()
384
QQmlComponent component(&engine, testFileUrl("/SizeToLoader.qml"));
385
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
386
QVERIFY(loader != 0);
387
QCOMPARE(loader->width(), 200.0);
388
QCOMPARE(loader->height(), 80.0);
390
QQuickItem *rect = qobject_cast<QQuickItem*>(loader->item());
392
QCOMPARE(rect->width(), 200.0);
393
QCOMPARE(rect->height(), 80.0);
396
loader->setWidth(180);
397
loader->setHeight(30);
398
QCOMPARE(rect->width(), 180.0);
399
QCOMPARE(rect->height(), 30.0);
402
loader->resetWidth(); // reset explicit size
403
loader->resetHeight();
406
QCOMPARE(loader->width(), 160.0);
407
QCOMPARE(loader->height(), 45.0);
412
void tst_QQuickLoader::noResize()
414
QQmlComponent component(&engine, testFileUrl("/NoResize.qml"));
415
QQuickItem* item = qobject_cast<QQuickItem*>(component.create());
417
QCOMPARE(item->width(), 200.0);
418
QCOMPARE(item->height(), 80.0);
423
void tst_QQuickLoader::networkRequestUrl()
425
TestHTTPServer server(SERVER_PORT);
426
QVERIFY(server.isValid());
427
server.serveDirectory(dataDirectory());
429
QQmlComponent component(&engine);
430
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"));
431
if (component.isError())
432
qDebug() << component.errors();
433
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
434
QVERIFY(loader != 0);
436
QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
438
QVERIFY(loader->item());
439
QCOMPARE(loader->progress(), 1.0);
440
QCOMPARE(loader->property("signalCount").toInt(), 1);
441
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
446
/* XXX Component waits until all dependencies are loaded. Is this actually possible? */
447
void tst_QQuickLoader::networkComponent()
449
TestHTTPServer server(SERVER_PORT);
450
QVERIFY(server.isValid());
451
server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
453
QQmlComponent component(&engine);
454
component.setData(QByteArray(
455
"import QtQuick 2.0\n"
456
"import \"http://127.0.0.1:14450/\" as NW\n"
458
" Component { id: comp; NW.Rect120x60 {} }\n"
459
" Loader { sourceComponent: comp } }")
462
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
465
QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::children().at(1));
467
QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
469
QVERIFY(loader->item());
470
QCOMPARE(loader->progress(), 1.0);
471
QCOMPARE(loader->status(), QQuickLoader::Ready);
472
QCOMPARE(static_cast<QQuickItem*>(loader)->children().count(), 1);
477
void tst_QQuickLoader::failNetworkRequest()
479
TestHTTPServer server(SERVER_PORT);
480
QVERIFY(server.isValid());
481
server.serveDirectory(dataDirectory());
483
QTest::ignoreMessage(QtWarningMsg, "http://127.0.0.1:14450/IDontExist.qml: File not found");
485
QQmlComponent component(&engine);
486
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"));
487
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
488
QVERIFY(loader != 0);
490
QTRY_VERIFY(loader->status() == QQuickLoader::Error);
492
QVERIFY(loader->item() == 0);
493
QCOMPARE(loader->progress(), 1.0);
494
QCOMPARE(loader->property("did_load").toInt(), 123);
495
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
500
void tst_QQuickLoader::active()
502
// check that the item isn't instantiated until active is set to true
504
QQmlComponent component(&engine, testFileUrl("active.1.qml"));
505
QObject *object = component.create();
506
QVERIFY(object != 0);
507
QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
509
QVERIFY(loader->active() == false); // set manually to false
510
QVERIFY(loader->item() == 0);
511
QMetaObject::invokeMethod(object, "doSetSourceComponent");
512
QVERIFY(loader->item() == 0);
513
QMetaObject::invokeMethod(object, "doSetSource");
514
QVERIFY(loader->item() == 0);
515
QMetaObject::invokeMethod(object, "doSetActive");
516
QVERIFY(loader->item() != 0);
521
// check that the status is Null if active is set to false
523
QQmlComponent component(&engine, testFileUrl("active.2.qml"));
524
QObject *object = component.create();
525
QVERIFY(object != 0);
526
QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
528
QVERIFY(loader->active() == true); // active is true by default
529
QCOMPARE(loader->status(), QQuickLoader::Ready);
530
int currStatusChangedCount = loader->property("statusChangedCount").toInt();
531
QMetaObject::invokeMethod(object, "doSetInactive");
532
QCOMPARE(loader->status(), QQuickLoader::Null);
533
QCOMPARE(loader->property("statusChangedCount").toInt(), (currStatusChangedCount+1));
538
// check that the source is not cleared if active is set to false
540
QQmlComponent component(&engine, testFileUrl("active.3.qml"));
541
QObject *object = component.create();
542
QVERIFY(object != 0);
543
QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
545
QVERIFY(loader->active() == true); // active is true by default
546
QVERIFY(!loader->source().isEmpty());
547
int currSourceChangedCount = loader->property("sourceChangedCount").toInt();
548
QMetaObject::invokeMethod(object, "doSetInactive");
549
QVERIFY(!loader->source().isEmpty());
550
QCOMPARE(loader->property("sourceChangedCount").toInt(), currSourceChangedCount);
555
// check that the sourceComponent is not cleared if active is set to false
557
QQmlComponent component(&engine, testFileUrl("active.4.qml"));
558
QObject *object = component.create();
559
QVERIFY(object != 0);
560
QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
562
QVERIFY(loader->active() == true); // active is true by default
563
QVERIFY(loader->sourceComponent() != 0);
564
int currSourceComponentChangedCount = loader->property("sourceComponentChangedCount").toInt();
565
QMetaObject::invokeMethod(object, "doSetInactive");
566
QVERIFY(loader->sourceComponent() != 0);
567
QCOMPARE(loader->property("sourceComponentChangedCount").toInt(), currSourceComponentChangedCount);
572
// check that the item is released if active is set to false
574
QQmlComponent component(&engine, testFileUrl("active.5.qml"));
575
QObject *object = component.create();
576
QVERIFY(object != 0);
577
QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
579
QVERIFY(loader->active() == true); // active is true by default
580
QVERIFY(loader->item() != 0);
581
int currItemChangedCount = loader->property("itemChangedCount").toInt();
582
QMetaObject::invokeMethod(object, "doSetInactive");
583
QVERIFY(loader->item() == 0);
584
QCOMPARE(loader->property("itemChangedCount").toInt(), (currItemChangedCount+1));
589
// check that the activeChanged signal is emitted correctly
591
QQmlComponent component(&engine, testFileUrl("active.6.qml"));
592
QObject *object = component.create();
593
QVERIFY(object != 0);
594
QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
596
QVERIFY(loader->active() == true); // active is true by default
597
loader->setActive(true); // no effect
598
QCOMPARE(loader->property("activeChangedCount").toInt(), 0);
599
loader->setActive(false); // change signal should be emitted
600
QCOMPARE(loader->property("activeChangedCount").toInt(), 1);
601
loader->setActive(false); // no effect
602
QCOMPARE(loader->property("activeChangedCount").toInt(), 1);
603
loader->setActive(true); // change signal should be emitted
604
QCOMPARE(loader->property("activeChangedCount").toInt(), 2);
605
loader->setActive(false); // change signal should be emitted
606
QCOMPARE(loader->property("activeChangedCount").toInt(), 3);
607
QMetaObject::invokeMethod(object, "doSetActive");
608
QCOMPARE(loader->property("activeChangedCount").toInt(), 4);
609
QMetaObject::invokeMethod(object, "doSetActive");
610
QCOMPARE(loader->property("activeChangedCount").toInt(), 4);
611
QMetaObject::invokeMethod(object, "doSetInactive");
612
QCOMPARE(loader->property("activeChangedCount").toInt(), 5);
613
loader->setActive(true); // change signal should be emitted
614
QCOMPARE(loader->property("activeChangedCount").toInt(), 6);
619
// check that the component isn't loaded until active is set to true
621
QQmlComponent component(&engine, testFileUrl("active.7.qml"));
622
QObject *object = component.create();
623
QVERIFY(object != 0);
624
QCOMPARE(object->property("success").toBool(), true);
628
// check that the component is loaded if active is not set (true by default)
630
QQmlComponent component(&engine, testFileUrl("active.8.qml"));
631
QObject *object = component.create();
632
QVERIFY(object != 0);
633
QCOMPARE(object->property("success").toBool(), true);
638
void tst_QQuickLoader::initialPropertyValues_data()
640
QTest::addColumn<QUrl>("qmlFile");
641
QTest::addColumn<QStringList>("expectedWarnings");
642
QTest::addColumn<QStringList>("propertyNames");
643
QTest::addColumn<QVariantList>("propertyValues");
645
QTest::newRow("source url with value set in onLoaded, initially active = true") << testFileUrl("initialPropertyValues.1.qml")
647
<< (QStringList() << "initialValue" << "behaviorCount")
648
<< (QVariantList() << 1 << 1);
650
QTest::newRow("set source with initial property values specified, active = true") << testFileUrl("initialPropertyValues.2.qml")
652
<< (QStringList() << "initialValue" << "behaviorCount")
653
<< (QVariantList() << 2 << 0);
655
QTest::newRow("set source with initial property values specified, active = false") << testFileUrl("initialPropertyValues.3.qml")
656
<< (QStringList() << QString(testFileUrl("initialPropertyValues.3.qml").toString() + QLatin1String(":16: TypeError: Cannot read property 'canary' of null")))
660
QTest::newRow("set source with initial property values specified, active = false, with active set true later") << testFileUrl("initialPropertyValues.4.qml")
662
<< (QStringList() << "initialValue" << "behaviorCount")
663
<< (QVariantList() << 4 << 0);
665
QTest::newRow("set source without initial property values specified, active = true") << testFileUrl("initialPropertyValues.5.qml")
667
<< (QStringList() << "initialValue" << "behaviorCount")
668
<< (QVariantList() << 0 << 0);
670
QTest::newRow("set source with initial property values specified with binding, active = true") << testFileUrl("initialPropertyValues.6.qml")
672
<< (QStringList() << "initialValue" << "behaviorCount")
673
<< (QVariantList() << 6 << 0);
675
QTest::newRow("ensure initial property value semantics mimic createObject") << testFileUrl("initialPropertyValues.7.qml")
677
<< (QStringList() << "loaderValue" << "createObjectValue")
678
<< (QVariantList() << 1 << 1);
680
QTest::newRow("ensure initial property values aren't disposed prior to component completion") << testFileUrl("initialPropertyValues.8.qml")
682
<< (QStringList() << "initialValue")
683
<< (QVariantList() << 6);
686
void tst_QQuickLoader::initialPropertyValues()
688
QFETCH(QUrl, qmlFile);
689
QFETCH(QStringList, expectedWarnings);
690
QFETCH(QStringList, propertyNames);
691
QFETCH(QVariantList, propertyValues);
693
TestHTTPServer server(SERVER_PORT);
694
QVERIFY(server.isValid());
695
server.serveDirectory(dataDirectory());
697
foreach (const QString &warning, expectedWarnings)
698
QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
700
QQmlComponent component(&engine, qmlFile);
701
QObject *object = component.create();
702
QVERIFY(object != 0);
703
qApp->processEvents();
706
for (int i = 0; i < propertyNames.size(); ++i)
707
QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
712
void tst_QQuickLoader::initialPropertyValuesBinding()
714
QQmlComponent component(&engine, testFileUrl("initialPropertyValues.binding.qml"));
715
QObject *object = component.create();
716
QVERIFY(object != 0);
718
QVERIFY(object->setProperty("bindable", QVariant(8)));
719
QCOMPARE(object->property("canaryValue").toInt(), 8);
724
void tst_QQuickLoader::initialPropertyValuesError_data()
726
QTest::addColumn<QUrl>("qmlFile");
727
QTest::addColumn<QStringList>("expectedWarnings");
729
QTest::newRow("invalid initial property values object") << testFileUrl("initialPropertyValues.error.1.qml")
730
<< (QStringList() << QString(testFileUrl("initialPropertyValues.error.1.qml").toString() + ":6:5: QML Loader: setSource: value is not an object"));
732
QTest::newRow("nonexistent source url") << testFileUrl("initialPropertyValues.error.2.qml")
733
<< (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": File not found"));
735
QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml")
736
<< (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
738
QTest::newRow("invalid initial property values object with invalid property access") << testFileUrl("initialPropertyValues.error.4.qml")
739
<< (QStringList() << QString(testFileUrl("initialPropertyValues.error.4.qml").toString() + ":7:5: QML Loader: setSource: value is not an object")
740
<< QString(testFileUrl("initialPropertyValues.error.4.qml").toString() + ":5: TypeError: Cannot read property 'canary' of null"));
743
void tst_QQuickLoader::initialPropertyValuesError()
745
QFETCH(QUrl, qmlFile);
746
QFETCH(QStringList, expectedWarnings);
748
foreach (const QString &warning, expectedWarnings)
749
QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
751
QQmlComponent component(&engine, qmlFile);
752
QObject *object = component.create();
753
QVERIFY(object != 0);
754
QQuickLoader *loader = object->findChild<QQuickLoader*>("loader");
755
QVERIFY(loader != 0);
756
QVERIFY(loader->item() == 0);
761
void tst_QQuickLoader::deleteComponentCrash()
763
QQmlComponent component(&engine, testFileUrl("crash.qml"));
764
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
767
item->metaObject()->invokeMethod(item, "setLoaderSource");
769
QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0));
771
QVERIFY(loader->item());
772
QCOMPARE(loader->item()->objectName(), QLatin1String("blue"));
773
QCOMPARE(loader->progress(), 1.0);
774
QCOMPARE(loader->status(), QQuickLoader::Ready);
775
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
776
QCoreApplication::processEvents();
777
QTRY_COMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
778
QVERIFY(loader->source() == testFileUrl("BlueRect.qml"));
783
void tst_QQuickLoader::nonItem()
785
QQmlComponent component(&engine, testFileUrl("nonItem.qml"));
786
QString err = testFileUrl("nonItem.qml").toString() + ":3:1: QML Loader: Loader does not support loading non-visual elements.";
788
QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
789
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
791
QVERIFY(loader->item() == 0);
796
void tst_QQuickLoader::vmeErrors()
798
QQmlComponent component(&engine, testFileUrl("vmeErrors.qml"));
799
QString err = testFileUrl("VmeError.qml").toString() + ":6: Cannot assign object type QObject with no default method";
800
QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData());
801
QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create());
803
QVERIFY(loader->item() == 0);
809
void tst_QQuickLoader::creationContext()
811
QQmlComponent component(&engine, testFileUrl("creationContext.qml"));
813
QObject *o = component.create();
816
QCOMPARE(o->property("test").toBool(), true);
821
void tst_QQuickLoader::QTBUG_16928()
823
QQmlComponent component(&engine, testFileUrl("QTBUG_16928.qml"));
824
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
827
QCOMPARE(item->width(), 250.);
828
QCOMPARE(item->height(), 250.);
833
void tst_QQuickLoader::implicitSize()
835
QQmlComponent component(&engine, testFileUrl("implicitSize.qml"));
836
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
839
QCOMPARE(item->width(), 150.);
840
QCOMPARE(item->height(), 150.);
842
QCOMPARE(item->property("implHeight").toReal(), 100.);
843
QCOMPARE(item->property("implWidth").toReal(), 100.);
845
QQuickLoader *loader = item->findChild<QQuickLoader*>("loader");
846
QSignalSpy implWidthSpy(loader, SIGNAL(implicitWidthChanged()));
847
QSignalSpy implHeightSpy(loader, SIGNAL(implicitHeightChanged()));
849
QMetaObject::invokeMethod(item, "changeImplicitSize");
851
QCOMPARE(loader->property("implicitWidth").toReal(), 200.);
852
QCOMPARE(loader->property("implicitHeight").toReal(), 300.);
854
QCOMPARE(implWidthSpy.count(), 1);
855
QCOMPARE(implHeightSpy.count(), 1);
860
void tst_QQuickLoader::QTBUG_17114()
862
QQmlComponent component(&engine, testFileUrl("QTBUG_17114.qml"));
863
QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
866
QCOMPARE(item->property("loaderWidth").toReal(), 32.);
867
QCOMPARE(item->property("loaderHeight").toReal(), 32.);
872
void tst_QQuickLoader::asynchronous_data()
874
QTest::addColumn<QUrl>("qmlFile");
875
QTest::addColumn<QStringList>("expectedWarnings");
877
QTest::newRow("Valid component") << testFileUrl("BigComponent.qml")
880
QTest::newRow("Non-existent component") << testFileUrl("IDoNotExist.qml")
881
<< (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": File not found"));
883
QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml")
884
<< (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error"));
887
void tst_QQuickLoader::asynchronous()
889
QFETCH(QUrl, qmlFile);
890
QFETCH(QStringList, expectedWarnings);
892
if (!engine.incubationController())
893
engine.setIncubationController(new PeriodicIncubationController);
894
PeriodicIncubationController *controller = static_cast<PeriodicIncubationController*>(engine.incubationController());
895
controller->incubated = false;
896
QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
897
QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
900
QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
903
foreach (const QString &warning, expectedWarnings)
904
QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
906
QVERIFY(!loader->item());
907
QCOMPARE(loader->progress(), 0.0);
908
root->setProperty("comp", qmlFile.toString());
909
QMetaObject::invokeMethod(root, "loadComponent");
910
QVERIFY(!loader->item());
912
if (expectedWarnings.isEmpty()) {
913
QCOMPARE(loader->status(), QQuickLoader::Loading);
914
QVERIFY(!controller->incubated); // asynchronous compilation means not immediately compiled/incubating.
915
QTRY_VERIFY(controller->incubated); // but should start incubating once compilation is complete.
916
QTRY_VERIFY(loader->item());
917
QCOMPARE(loader->progress(), 1.0);
918
QCOMPARE(loader->status(), QQuickLoader::Ready);
920
QTRY_COMPARE(loader->progress(), 1.0);
921
QTRY_COMPARE(loader->status(), QQuickLoader::Error);
927
void tst_QQuickLoader::asynchronous_clear()
929
if (!engine.incubationController())
930
engine.setIncubationController(new PeriodicIncubationController);
931
QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
932
QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
935
QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
938
QVERIFY(!loader->item());
939
root->setProperty("comp", "BigComponent.qml");
940
QMetaObject::invokeMethod(root, "loadComponent");
941
QVERIFY(!loader->item());
943
QCOMPARE(loader->status(), QQuickLoader::Loading);
944
QTRY_COMPARE(engine.incubationController()->incubatingObjectCount(), 1);
946
// clear before component created
947
root->setProperty("comp", "");
948
QMetaObject::invokeMethod(root, "loadComponent");
949
QVERIFY(!loader->item());
950
QCOMPARE(engine.incubationController()->incubatingObjectCount(), 0);
952
QCOMPARE(loader->progress(), 0.0);
953
QCOMPARE(loader->status(), QQuickLoader::Null);
954
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
956
// check loading component
957
root->setProperty("comp", "BigComponent.qml");
958
QMetaObject::invokeMethod(root, "loadComponent");
959
QVERIFY(!loader->item());
961
QCOMPARE(loader->status(), QQuickLoader::Loading);
962
QCOMPARE(engine.incubationController()->incubatingObjectCount(), 1);
964
QTRY_VERIFY(loader->item());
965
QCOMPARE(loader->progress(), 1.0);
966
QCOMPARE(loader->status(), QQuickLoader::Ready);
967
QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
972
void tst_QQuickLoader::simultaneousSyncAsync()
974
if (!engine.incubationController())
975
engine.setIncubationController(new PeriodicIncubationController);
976
PeriodicIncubationController *controller = static_cast<PeriodicIncubationController*>(engine.incubationController());
977
controller->incubated = false;
978
QQmlComponent component(&engine, testFileUrl("simultaneous.qml"));
979
QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
982
QQuickLoader *asyncLoader = root->findChild<QQuickLoader*>("asyncLoader");
983
QQuickLoader *syncLoader = root->findChild<QQuickLoader*>("syncLoader");
984
QVERIFY(asyncLoader);
987
QVERIFY(!asyncLoader->item());
988
QVERIFY(!syncLoader->item());
989
QMetaObject::invokeMethod(root, "loadComponents");
990
QVERIFY(!asyncLoader->item());
991
QVERIFY(syncLoader->item());
993
QCOMPARE(asyncLoader->status(), QQuickLoader::Loading);
994
QVERIFY(!controller->incubated); // asynchronous compilation means not immediately compiled/incubating.
995
QTRY_VERIFY(controller->incubated); // but should start incubating once compilation is complete.
996
QTRY_VERIFY(asyncLoader->item());
997
QCOMPARE(asyncLoader->progress(), 1.0);
998
QCOMPARE(asyncLoader->status(), QQuickLoader::Ready);
1003
void tst_QQuickLoader::loadedSignal()
1006
// ensure that triggering loading (by setting active = true)
1007
// and then immediately setting active to false, causes the
1008
// loader to be deactivated, including disabling the incubator.
1009
QQmlComponent component(&engine, testFileUrl("loadedSignal.qml"));
1010
QObject *obj = component.create();
1012
QMetaObject::invokeMethod(obj, "triggerLoading");
1013
QTest::qWait(100); // ensure that loading would have finished if it wasn't deactivated
1014
QCOMPARE(obj->property("loadCount").toInt(), 0);
1015
QVERIFY(obj->property("success").toBool());
1017
QMetaObject::invokeMethod(obj, "triggerLoading");
1019
QCOMPARE(obj->property("loadCount").toInt(), 0);
1020
QVERIFY(obj->property("success").toBool());
1022
QMetaObject::invokeMethod(obj, "triggerMultipleLoad");
1024
QCOMPARE(obj->property("loadCount").toInt(), 1); // only one loaded signal should be emitted.
1025
QVERIFY(obj->property("success").toBool());
1031
// ensure that an error doesn't result in the onLoaded signal being emitted.
1032
QQmlComponent component(&engine, testFileUrl("loadedSignal.2.qml"));
1033
QObject *obj = component.create();
1035
QMetaObject::invokeMethod(obj, "triggerLoading");
1037
QCOMPARE(obj->property("loadCount").toInt(), 0);
1038
QVERIFY(obj->property("success").toBool());
1044
void tst_QQuickLoader::parented()
1046
QQmlComponent component(&engine, testFileUrl("parented.qml"));
1047
QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
1050
QQuickItem *item = root->findChild<QQuickItem*>("comp");
1053
QVERIFY(item->parentItem() == root);
1055
QCOMPARE(item->width(), 300.);
1056
QCOMPARE(item->height(), 300.);
1061
void tst_QQuickLoader::sizeBound()
1063
QQmlComponent component(&engine, testFileUrl("sizebound.qml"));
1064
QQuickItem *root = qobject_cast<QQuickItem*>(component.create());
1066
QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
1067
QVERIFY(loader != 0);
1069
QVERIFY(loader->item());
1071
QCOMPARE(loader->width(), 50.0);
1072
QCOMPARE(loader->height(), 60.0);
1074
QMetaObject::invokeMethod(root, "switchComponent");
1076
QCOMPARE(loader->width(), 80.0);
1077
QCOMPARE(loader->height(), 90.0);
1083
QTEST_MAIN(tst_QQuickLoader)
1085
#include "tst_qquickloader.moc"