1/****************************************************************************
2**
3** Copyright (C) 2016 Research In Motion.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28#include <qtest.h>
29#include <QSignalSpy>
30#include <QDebug>
31
32#include <QtQml/qqmlengine.h>
33#include <QtQml/qqmlcomponent.h>
34#include <QtQmlModels/private/qqmlinstantiator_p.h>
35#include <QtQml/qqmlcontext.h>
36#include <QtQml/qqmlincubator.h>
37#include "../../shared/util.h"
38#include "stringmodel.h"
39
40class tst_qqmlinstantiator: public QQmlDataTest
41{
42 Q_OBJECT
43
44private slots:
45 void createNone();
46 void createSingle();
47 void createMultiple();
48 void stringModel();
49 void activeProperty();
50 void activeModelChangeInteraction();
51 void intModelChange();
52 void createAndRemove();
53
54 void asynchronous_data();
55 void asynchronous();
56};
57
58void tst_qqmlinstantiator::createNone()
59{
60 QQmlEngine engine;
61 QQmlComponent component(&engine, testFileUrl(fileName: "createNone.qml"));
62 QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(object: component.create());
63 QVERIFY(instantiator != nullptr);
64 QCOMPARE(instantiator->isActive(), true);
65 QCOMPARE(instantiator->count(), 0);
66 QCOMPARE(instantiator->property("success").toBool(), true);
67 QVERIFY(instantiator->delegate()->isReady());
68}
69
70void tst_qqmlinstantiator::createSingle()
71{
72 QQmlEngine engine;
73 QQmlComponent component(&engine, testFileUrl(fileName: "createSingle.qml"));
74 QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(object: component.create());
75 QVERIFY(instantiator != nullptr);
76 QCOMPARE(instantiator->isActive(), true);
77 QCOMPARE(instantiator->count(), 1);
78 QVERIFY(instantiator->delegate()->isReady());
79
80 QObject *object = instantiator->object();
81 QVERIFY(object);
82 QCOMPARE(object->parent(), instantiator);
83 QCOMPARE(object->property("success").toBool(), true);
84 QCOMPARE(object->property("idx").toInt(), 0);
85}
86
87void tst_qqmlinstantiator::createMultiple()
88{
89 QQmlEngine engine;
90 QQmlComponent component(&engine, testFileUrl(fileName: "createMultiple.qml"));
91 QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(object: component.create());
92 QVERIFY(instantiator != nullptr);
93 QCOMPARE(instantiator->isActive(), true);
94 QCOMPARE(instantiator->count(), 10);
95
96 for (int i=0; i<10; i++) {
97 QObject *object = instantiator->objectAt(index: i);
98 QVERIFY(object);
99 QCOMPARE(object->parent(), instantiator);
100 QCOMPARE(object->property("success").toBool(), true);
101 QCOMPARE(object->property("idx").toInt(), i);
102 }
103}
104
105void tst_qqmlinstantiator::stringModel()
106{
107 QQmlEngine engine;
108 QQmlComponent component(&engine, testFileUrl(fileName: "stringModel.qml"));
109 QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(object: component.create());
110 QVERIFY(instantiator != nullptr);
111 QCOMPARE(instantiator->isActive(), true);
112 QCOMPARE(instantiator->count(), 4);
113
114 for (int i=0; i<4; i++) {
115 QObject *object = instantiator->objectAt(index: i);
116 QVERIFY(object);
117 QCOMPARE(object->parent(), instantiator);
118 QCOMPARE(object->property("success").toBool(), true);
119 }
120}
121
122void tst_qqmlinstantiator::activeProperty()
123{
124 QQmlEngine engine;
125 QQmlComponent component(&engine, testFileUrl(fileName: "inactive.qml"));
126 QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(object: component.create());
127 QVERIFY(instantiator != nullptr);
128 QSignalSpy activeSpy(instantiator, SIGNAL(activeChanged()));
129 QSignalSpy countSpy(instantiator, SIGNAL(countChanged()));
130 QSignalSpy objectSpy(instantiator, SIGNAL(objectChanged()));
131 QSignalSpy modelSpy(instantiator, SIGNAL(modelChanged()));
132 QCOMPARE(instantiator->isActive(), false);
133 QCOMPARE(instantiator->count(), 0);
134 QVERIFY(instantiator->delegate()->isReady());
135
136 QCOMPARE(activeSpy.count(), 0);
137 QCOMPARE(countSpy.count(), 0);
138 QCOMPARE(objectSpy.count(), 0);
139 QCOMPARE(modelSpy.count(), 0);
140
141 instantiator->setActive(true);
142 QCOMPARE(instantiator->isActive(), true);
143 QCOMPARE(instantiator->count(), 1);
144
145 QCOMPARE(activeSpy.count(), 1);
146 QCOMPARE(countSpy.count(), 1);
147 QCOMPARE(objectSpy.count(), 1);
148 QCOMPARE(modelSpy.count(), 0);
149
150 QObject *object = instantiator->object();
151 QVERIFY(object);
152 QCOMPARE(object->parent(), instantiator);
153 QCOMPARE(object->property("success").toBool(), true);
154 QCOMPARE(object->property("idx").toInt(), 0);
155}
156
157void tst_qqmlinstantiator::activeModelChangeInteraction()
158{
159 QQmlEngine engine;
160 QQmlComponent component(&engine, testFileUrl(fileName: "activeModelChangeInteraction.qml"));
161 QScopedPointer<QObject> root(component.create());
162 QVERIFY(root);
163
164 // If the instantiator is inactive, a model change does not lead to items being loaded
165 bool ok = false;
166 int count = root->property(name: "instanceCount").toInt(ok: &ok);
167 QVERIFY(ok);
168 QCOMPARE(count, 0);
169
170 // When turning the instantiator active, it will however reflect the model
171 root->setProperty(name: "active", value: true);
172 count = root->property(name: "instanceCount").toInt(ok: &ok);
173 QVERIFY(ok);
174 QCOMPARE(count, 3);
175}
176
177void tst_qqmlinstantiator::intModelChange()
178{
179 QQmlEngine engine;
180 QQmlComponent component(&engine, testFileUrl(fileName: "createMultiple.qml"));
181 QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(object: component.create());
182 QVERIFY(instantiator != nullptr);
183 QSignalSpy activeSpy(instantiator, SIGNAL(activeChanged()));
184 QSignalSpy countSpy(instantiator, SIGNAL(countChanged()));
185 QSignalSpy objectSpy(instantiator, SIGNAL(objectChanged()));
186 QSignalSpy modelSpy(instantiator, SIGNAL(modelChanged()));
187 QCOMPARE(instantiator->count(), 10);
188
189 QCOMPARE(activeSpy.count(), 0);
190 QCOMPARE(countSpy.count(), 0);
191 QCOMPARE(objectSpy.count(), 0);
192 QCOMPARE(modelSpy.count(), 0);
193
194 instantiator->setModel(QVariant(2));
195 QCOMPARE(instantiator->count(), 2);
196
197 QCOMPARE(activeSpy.count(), 0);
198 QCOMPARE(countSpy.count(), 1);
199 QCOMPARE(objectSpy.count(), 2);
200 QCOMPARE(modelSpy.count(), 1);
201
202 for (int i=0; i<2; i++) {
203 QObject *object = instantiator->objectAt(index: i);
204 QVERIFY(object);
205 QCOMPARE(object->parent(), instantiator);
206 QCOMPARE(object->property("success").toBool(), true);
207 QCOMPARE(object->property("idx").toInt(), i);
208 }
209}
210
211void tst_qqmlinstantiator::createAndRemove()
212{
213 QQmlEngine engine;
214 QScopedPointer<StringModel> model {new StringModel("model1")};
215 qmlRegisterSingletonInstance(uri: "Test", versionMajor: 1, versionMinor: 0, typeName: "Model1", cppObject: model.get());
216 QQmlComponent component(&engine, testFileUrl(fileName: "createAndRemove.qml"));
217 QObject *rootObject = component.create();
218 QVERIFY(rootObject != nullptr);
219
220 QQmlInstantiator *instantiator =
221 qobject_cast<QQmlInstantiator*>(object: rootObject->findChild<QObject*>(aName: "instantiator1"));
222 QVERIFY(instantiator != nullptr);
223 model->drop(count: 1);
224 QVector<QString> names;
225 names << "Beta" << "Gamma" << "Delta";
226 for (int i=0; i<3; i++) {
227 QObject *object = instantiator->objectAt(index: i);
228 QVERIFY(object);
229 QCOMPARE(object->property("datum").toString(), names[i]);
230 }
231}
232
233void tst_qqmlinstantiator::asynchronous_data()
234{
235 QTest::addColumn<bool>(name: "asyncIncubator");
236 QTest::addColumn<QString>(name: "fileName");
237
238 QTest::newRow(dataTag: "Asynchronous Instantiator") << false << "createMultipleAsync.qml";
239 QTest::newRow(dataTag: "Nested-asynchronous Instantiator") << true << "createMultiple.qml";
240}
241
242void tst_qqmlinstantiator::asynchronous()
243{
244 QFETCH(bool, asyncIncubator);
245 QFETCH(QString, fileName);
246
247 QQmlEngine engine;
248 QQmlIncubationController incubationController;
249 engine.setIncubationController(&incubationController);
250 QQmlComponent component(&engine, testFileUrl(fileName));
251 QQmlIncubator incubator(asyncIncubator ? QQmlIncubator::Asynchronous : QQmlIncubator::Synchronous);
252 component.create(incubator);
253 while (!incubator.isReady())
254 incubationController.incubateFor(msecs: 10);
255 QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator *>(object: incubator.object());
256 while (incubationController.incubatingObjectCount() > 0)
257 incubationController.incubateFor(msecs: 10);
258 QVERIFY(instantiator != nullptr);
259 QCOMPARE(instantiator->isActive(), true);
260 QCOMPARE(instantiator->count(), 10);
261
262 for (int i=0; i<10; i++) {
263 QObject *object = instantiator->objectAt(index: i);
264 QVERIFY(object);
265 QCOMPARE(object->parent(), instantiator);
266 QCOMPARE(object->property("success").toBool(), true);
267 QCOMPARE(object->property("idx").toInt(), i);
268 }
269}
270
271QTEST_MAIN(tst_qqmlinstantiator)
272
273#include "tst_qqmlinstantiator.moc"
274

source code of qtdeclarative/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp