1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
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
29#include <qtest.h>
30#include <private/qqmlpropertycache_p.h>
31#include <QtQml/qqmlengine.h>
32#include <QtQml/qqmlcontext.h>
33#include <QtQml/qqmlcomponent.h>
34#include <private/qmetaobjectbuilder_p.h>
35#include <QCryptographicHash>
36#include "../../shared/util.h"
37
38class tst_qqmlpropertycache : public QQmlDataTest
39{
40 Q_OBJECT
41public:
42 tst_qqmlpropertycache() {}
43
44private slots:
45 void properties();
46 void propertiesDerived();
47 void revisionedProperties();
48 void methods();
49 void methodsDerived();
50 void signalHandlers();
51 void signalHandlersDerived();
52 void passForeignEnums();
53 void passQGadget();
54 void metaObjectSize_data();
55 void metaObjectSize();
56 void metaObjectChecksum();
57 void metaObjectsForRootElements();
58 void derivedGadgetMethod();
59
60private:
61 QQmlEngine engine;
62};
63
64class BaseGadget
65{
66 Q_GADGET
67 QML_ANONYMOUS
68public:
69 Q_INVOKABLE QString stringValue() { return QLatin1String("base"); }
70};
71
72Q_DECLARE_METATYPE(BaseGadget)
73
74class DerivedGadget : public BaseGadget
75{
76 Q_GADGET
77 QML_ANONYMOUS
78public:
79 Q_INVOKABLE QString stringValue() { return QLatin1String("derived"); }
80};
81
82Q_DECLARE_METATYPE(DerivedGadget)
83
84class GadgetUser : public QObject
85{
86 Q_OBJECT
87 Q_PROPERTY(BaseGadget base READ base CONSTANT)
88 Q_PROPERTY(DerivedGadget derived READ derived CONSTANT)
89 Q_PROPERTY(QString baseString READ baseString WRITE setBaseString NOTIFY baseStringChanged)
90 Q_PROPERTY(QString derivedString READ derivedString WRITE setDerivedString NOTIFY derivedStringChanged)
91 QML_ELEMENT
92
93public:
94 BaseGadget base() const { return m_base; }
95 DerivedGadget derived() const { return m_derived; }
96 QString baseString() const { return m_baseString; }
97 QString derivedString() const { return m_derivedString; }
98
99public slots:
100 void setBaseString(QString baseString)
101 {
102 if (m_baseString == baseString)
103 return;
104
105 m_baseString = baseString;
106 emit baseStringChanged(baseString: m_baseString);
107 }
108
109 void setDerivedString(QString derivedString)
110 {
111 if (m_derivedString == derivedString)
112 return;
113
114 m_derivedString = derivedString;
115 emit derivedStringChanged(derivedString: m_derivedString);
116 }
117
118signals:
119 void baseStringChanged(QString baseString);
120 void derivedStringChanged(QString derivedString);
121
122private:
123 BaseGadget m_base;
124 DerivedGadget m_derived;
125 QString m_baseString;
126 QString m_derivedString;
127};
128
129class BaseObject : public QObject
130{
131 Q_OBJECT
132 Q_PROPERTY(int propertyA READ propertyA NOTIFY propertyAChanged)
133 Q_PROPERTY(QString propertyB READ propertyB NOTIFY propertyBChanged)
134public:
135 BaseObject(QObject *parent = nullptr) : QObject(parent) {}
136
137 int propertyA() const { return 0; }
138 QString propertyB() const { return QString(); }
139
140public Q_SLOTS:
141 void slotA() {}
142
143Q_SIGNALS:
144 void propertyAChanged();
145 void propertyBChanged();
146 void signalA();
147};
148
149class DerivedObject : public BaseObject
150{
151 Q_OBJECT
152 Q_PROPERTY(int propertyC READ propertyC NOTIFY propertyCChanged)
153 Q_PROPERTY(QString propertyD READ propertyD NOTIFY propertyDChanged)
154 Q_PROPERTY(int propertyE READ propertyE NOTIFY propertyEChanged REVISION 1)
155public:
156 DerivedObject(QObject *parent = nullptr) : BaseObject(parent) {}
157
158 int propertyC() const { return 0; }
159 QString propertyD() const { return QString(); }
160 int propertyE() const { return 0; }
161
162public Q_SLOTS:
163 void slotB() {}
164
165Q_SIGNALS:
166 void propertyCChanged();
167 void propertyDChanged();
168 Q_REVISION(1) void propertyEChanged();
169 void signalB();
170};
171
172QQmlPropertyData *cacheProperty(const QQmlRefPointer<QQmlPropertyCache> &cache, const char *name)
173{
174 return cache->property(key: QLatin1String(name), object: nullptr, context: nullptr);
175}
176
177void tst_qqmlpropertycache::properties()
178{
179 QQmlEngine engine;
180 DerivedObject object;
181 const QMetaObject *metaObject = object.metaObject();
182
183 QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(metaObject));
184 QQmlPropertyData *data;
185
186 QVERIFY((data = cacheProperty(cache, "propertyA")));
187 QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA"));
188
189 QVERIFY((data = cacheProperty(cache, "propertyB")));
190 QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyB"));
191
192 QVERIFY((data = cacheProperty(cache, "propertyC")));
193 QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyC"));
194
195 QVERIFY((data = cacheProperty(cache, "propertyD")));
196 QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD"));
197}
198
199void tst_qqmlpropertycache::propertiesDerived()
200{
201 QQmlEngine engine;
202 DerivedObject object;
203 const QMetaObject *metaObject = object.metaObject();
204
205 QQmlRefPointer<QQmlPropertyCache> parentCache(new QQmlPropertyCache(&BaseObject::staticMetaObject));
206 QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
207 QQmlPropertyData *data;
208
209 QVERIFY((data = cacheProperty(cache, "propertyA")));
210 QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA"));
211
212 QVERIFY((data = cacheProperty(cache, "propertyB")));
213 QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyB"));
214
215 QVERIFY((data = cacheProperty(cache, "propertyC")));
216 QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyC"));
217
218 QVERIFY((data = cacheProperty(cache, "propertyD")));
219 QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD"));
220}
221
222void tst_qqmlpropertycache::revisionedProperties()
223{
224 // Check that if you create a QQmlPropertyCache from a QMetaObject together
225 // with an explicit revision, the cache will then, and only then, report a
226 // property with a matching revision as available.
227 DerivedObject object;
228 const QMetaObject *metaObject = object.metaObject();
229
230 QQmlRefPointer<QQmlPropertyCache> cacheWithoutVersion(new QQmlPropertyCache(metaObject));
231 QQmlRefPointer<QQmlPropertyCache> cacheWithVersion(new QQmlPropertyCache(metaObject, 1));
232 QQmlPropertyData *data;
233
234 QVERIFY((data = cacheProperty(cacheWithoutVersion, "propertyE")));
235 QCOMPARE(cacheWithoutVersion->isAllowedInRevision(data), false);
236 QCOMPARE(cacheWithVersion->isAllowedInRevision(data), true);
237}
238
239void tst_qqmlpropertycache::methods()
240{
241 QQmlEngine engine;
242 DerivedObject object;
243 const QMetaObject *metaObject = object.metaObject();
244
245 QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(metaObject));
246 QQmlPropertyData *data;
247
248 QVERIFY((data = cacheProperty(cache, "slotA")));
249 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotA()"));
250
251 QVERIFY((data = cacheProperty(cache, "slotB")));
252 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotB()"));
253
254 QVERIFY((data = cacheProperty(cache, "signalA")));
255 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()"));
256
257 QVERIFY((data = cacheProperty(cache, "signalB")));
258 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()"));
259
260 QVERIFY((data = cacheProperty(cache, "propertyAChanged")));
261 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()"));
262
263 QVERIFY((data = cacheProperty(cache, "propertyBChanged")));
264 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()"));
265
266 QVERIFY((data = cacheProperty(cache, "propertyCChanged")));
267 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()"));
268
269 QVERIFY((data = cacheProperty(cache, "propertyDChanged")));
270 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()"));
271}
272
273void tst_qqmlpropertycache::methodsDerived()
274{
275 QQmlEngine engine;
276 DerivedObject object;
277 const QMetaObject *metaObject = object.metaObject();
278
279 QQmlRefPointer<QQmlPropertyCache> parentCache(new QQmlPropertyCache(&BaseObject::staticMetaObject));
280 QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
281 QQmlPropertyData *data;
282
283 QVERIFY((data = cacheProperty(cache, "slotA")));
284 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotA()"));
285
286 QVERIFY((data = cacheProperty(cache, "slotB")));
287 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotB()"));
288
289 QVERIFY((data = cacheProperty(cache, "signalA")));
290 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()"));
291
292 QVERIFY((data = cacheProperty(cache, "signalB")));
293 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()"));
294
295 QVERIFY((data = cacheProperty(cache, "propertyAChanged")));
296 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()"));
297
298 QVERIFY((data = cacheProperty(cache, "propertyBChanged")));
299 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()"));
300
301 QVERIFY((data = cacheProperty(cache, "propertyCChanged")));
302 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()"));
303
304 QVERIFY((data = cacheProperty(cache, "propertyDChanged")));
305 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()"));
306}
307
308void tst_qqmlpropertycache::signalHandlers()
309{
310 QQmlEngine engine;
311 DerivedObject object;
312 const QMetaObject *metaObject = object.metaObject();
313
314 QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(metaObject));
315 QQmlPropertyData *data;
316
317 QVERIFY((data = cacheProperty(cache, "onSignalA")));
318 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()"));
319
320 QVERIFY((data = cacheProperty(cache, "onSignalB")));
321 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()"));
322
323 QVERIFY((data = cacheProperty(cache, "onPropertyAChanged")));
324 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()"));
325
326 QVERIFY((data = cacheProperty(cache, "onPropertyBChanged")));
327 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()"));
328
329 QVERIFY((data = cacheProperty(cache, "onPropertyCChanged")));
330 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()"));
331
332 QVERIFY((data = cacheProperty(cache, "onPropertyDChanged")));
333 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()"));
334}
335
336void tst_qqmlpropertycache::signalHandlersDerived()
337{
338 QQmlEngine engine;
339 DerivedObject object;
340 const QMetaObject *metaObject = object.metaObject();
341
342 QQmlRefPointer<QQmlPropertyCache> parentCache(new QQmlPropertyCache(&BaseObject::staticMetaObject));
343 QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject()));
344 QQmlPropertyData *data;
345
346 QVERIFY((data = cacheProperty(cache, "onSignalA")));
347 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()"));
348
349 QVERIFY((data = cacheProperty(cache, "onSignalB")));
350 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()"));
351
352 QVERIFY((data = cacheProperty(cache, "onPropertyAChanged")));
353 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()"));
354
355 QVERIFY((data = cacheProperty(cache, "onPropertyBChanged")));
356 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()"));
357
358 QVERIFY((data = cacheProperty(cache, "onPropertyCChanged")));
359 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()"));
360
361 QVERIFY((data = cacheProperty(cache, "onPropertyDChanged")));
362 QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()"));
363}
364
365class MyEnum : public QObject
366 {
367 Q_OBJECT
368 public:
369 enum Option1Flag {
370 Option10 = 0,
371 Option1A = 1,
372 Option1B = 2,
373 Option1C = 4,
374 Option1D = 8,
375 Option1E = 16,
376 Option1F = 32,
377 Option1AD = Option1A | Option1D,
378 };
379 Q_DECLARE_FLAGS(Option1, Option1Flag)
380 Q_FLAG(Option1)
381
382 enum ShortEnum: quint16 {
383 Short0 = 0,
384 Short8 = 0xff,
385 Short16 = 0xffff
386 };
387 Q_ENUM(ShortEnum);
388};
389
390class MyData : public QObject
391{
392 Q_OBJECT
393 Q_PROPERTY(MyEnum::Option1 opt1 READ opt1 WRITE setOpt1 NOTIFY opt1Changed)
394 Q_PROPERTY(MyEnum::ShortEnum opt2 READ opt2 WRITE setOpt2 NOTIFY opt2Changed)
395public:
396 MyEnum::Option1 opt1() const { return m_opt1; }
397 MyEnum::ShortEnum opt2() const { return m_opt2; }
398
399signals:
400 void opt1Changed(MyEnum::Option1 opt1);
401 void opt2Changed(MyEnum::ShortEnum opt2);
402
403public slots:
404 void setOpt1(MyEnum::Option1 opt1)
405 {
406 QCOMPARE(opt1, MyEnum::Option1AD);
407 if (opt1 != m_opt1) {
408 m_opt1 = opt1;
409 emit opt1Changed(opt1);
410 }
411 }
412
413 void setOpt2(MyEnum::ShortEnum opt2)
414 {
415 QCOMPARE(opt2, MyEnum::Short16);
416 if (opt2 != m_opt2) {
417 m_opt2 = opt2;
418 emit opt2Changed(opt2);
419 }
420 }
421
422 void setOption1(MyEnum::Option1 opt1) { setOpt1(opt1); }
423 void setOption2(MyEnum::ShortEnum opt2) { setOpt2(opt2); }
424
425private:
426 MyEnum::Option1 m_opt1 = MyEnum::Option10;
427 MyEnum::ShortEnum m_opt2 = MyEnum::Short8;
428};
429
430void tst_qqmlpropertycache::passForeignEnums()
431{
432 qmlRegisterType<MyEnum>(uri: "example", versionMajor: 1, versionMinor: 0, qmlName: "MyEnum");
433 qmlRegisterType<MyData>(uri: "example", versionMajor: 1, versionMinor: 0, qmlName: "MyData");
434
435 MyEnum myenum;
436 MyData data;
437
438 engine.rootContext()->setContextProperty("myenum", &myenum);
439 engine.rootContext()->setContextProperty("mydata", &data);
440
441 QQmlComponent component(&engine, testFile(fileName: "foreignEnums.qml"));
442 QVERIFY(component.isReady());
443
444 QScopedPointer<QObject> obj(component.create(context: engine.rootContext()));
445 QVERIFY(!obj.isNull());
446 QCOMPARE(data.opt1(), MyEnum::Option1AD);
447 QCOMPARE(data.opt2(), MyEnum::Short16);
448}
449
450Q_DECLARE_METATYPE(MyEnum::Option1)
451Q_DECLARE_METATYPE(MyEnum::ShortEnum)
452
453QT_BEGIN_NAMESPACE
454class SimpleGadget
455{
456 Q_GADGET
457 Q_PROPERTY(bool someProperty READ someProperty)
458public:
459 bool someProperty() const { return true; }
460};
461
462// Avoids NeedsCreation and NeedsDestruction flags
463Q_DECLARE_TYPEINFO(SimpleGadget, Q_PRIMITIVE_TYPE);
464QT_END_NAMESPACE
465
466class GadgetEmitter : public QObject
467{
468 Q_OBJECT
469signals:
470 void emitGadget(SimpleGadget);
471};
472
473void tst_qqmlpropertycache::passQGadget()
474{
475 qRegisterMetaType<SimpleGadget>();
476
477 GadgetEmitter emitter;
478 engine.rootContext()->setContextProperty("emitter", &emitter);
479 QQmlComponent component(&engine, testFile(fileName: "passQGadget.qml"));
480 QVERIFY(component.isReady());
481
482 QScopedPointer<QObject> obj(component.create(context: engine.rootContext()));
483 QVariant before = obj->property(name: "result");
484 QVERIFY(before.isNull());
485 emit emitter.emitGadget(SimpleGadget());
486 QVariant after = obj->property(name: "result");
487 QCOMPARE(QMetaType::Type(after.type()), QMetaType::Bool);
488 QVERIFY(after.toBool());
489}
490
491class TestClass : public QObject
492{
493 Q_OBJECT
494 Q_PROPERTY(int prop READ prop WRITE setProp NOTIFY propChanged)
495 int m_prop;
496
497public:
498 enum MyEnum {
499 First, Second
500 };
501 Q_ENUM(MyEnum)
502
503 Q_CLASSINFO("Foo", "Bar")
504
505 TestClass() {}
506
507 int prop() const
508 {
509 return m_prop;
510 }
511
512public slots:
513 void setProp(int prop)
514 {
515 if (m_prop == prop)
516 return;
517
518 m_prop = prop;
519 emit propChanged(prop);
520 }
521signals:
522 void propChanged(int prop);
523};
524
525class TestClassWithParameters : public QObject
526{
527 Q_OBJECT
528
529public:
530 Q_INVOKABLE void slotWithArguments(int firstArg) {
531 Q_UNUSED(firstArg);
532 }
533};
534
535class TestClassWithClassInfo : public QObject
536{
537 Q_OBJECT
538 Q_CLASSINFO("Key", "Value")
539};
540
541#include "tst_qqmlpropertycache.moc"
542
543#define ARRAY_SIZE(arr) \
544 int(sizeof(arr) / sizeof(arr[0]))
545
546#define TEST_CLASS(Class) \
547 QTest::newRow(#Class) << &Class::staticMetaObject << ARRAY_SIZE(qt_meta_data_##Class) << ARRAY_SIZE(qt_meta_stringdata_##Class.data)
548
549Q_DECLARE_METATYPE(const QMetaObject*);
550
551void tst_qqmlpropertycache::metaObjectSize_data()
552{
553 QTest::addColumn<const QMetaObject*>(name: "metaObject");
554 QTest::addColumn<int>(name: "expectedFieldCount");
555 QTest::addColumn<int>(name: "expectedStringCount");
556
557 TEST_CLASS(TestClass);
558 TEST_CLASS(TestClassWithParameters);
559 TEST_CLASS(TestClassWithClassInfo);
560}
561
562void tst_qqmlpropertycache::metaObjectSize()
563{
564 QFETCH(const QMetaObject *, metaObject);
565 QFETCH(int, expectedFieldCount);
566 QFETCH(int, expectedStringCount);
567
568 int size = 0;
569 int stringDataSize = 0;
570 bool valid = QQmlPropertyCache::determineMetaObjectSizes(mo: *metaObject, fieldCount: &size, stringCount: &stringDataSize);
571 QVERIFY(valid);
572
573 QCOMPARE(size, expectedFieldCount - 1); // Remove trailing zero field until fixed in moc.
574 QCOMPARE(stringDataSize, expectedStringCount);
575}
576
577void tst_qqmlpropertycache::metaObjectChecksum()
578{
579 QMetaObjectBuilder builder;
580 builder.setClassName("Test");
581 builder.addClassInfo(name: "foo", value: "bar");
582
583 QCryptographicHash hash(QCryptographicHash::Md5);
584
585 QScopedPointer<QMetaObject, QScopedPointerPodDeleter> mo(builder.toMetaObject());
586 QVERIFY(!mo.isNull());
587
588 QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data()));
589 QByteArray initialHash = hash.result();
590 QVERIFY(!initialHash.isEmpty());
591 hash.reset();
592
593 {
594 QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data()));
595 QByteArray nextHash = hash.result();
596 QVERIFY(!nextHash.isEmpty());
597 hash.reset();
598 QCOMPARE(initialHash, nextHash);
599 }
600
601 builder.addProperty(name: "testProperty", type: "int", notifierId: -1);
602
603 mo.reset(other: builder.toMetaObject());
604 {
605 QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data()));
606 QByteArray nextHash = hash.result();
607 QVERIFY(!nextHash.isEmpty());
608 hash.reset();
609 QVERIFY(initialHash != nextHash);
610 }
611}
612
613void tst_qqmlpropertycache::metaObjectsForRootElements()
614{
615 QQmlEngine engine;
616 QQmlComponent c(&engine, testFileUrl(fileName: "noDuckType.qml"));
617 QVERIFY(c.isReady());
618 QScopedPointer<QObject> obj(c.create());
619 QVERIFY(!obj.isNull());
620 QCOMPARE(obj->property("result").toString(), QString::fromLatin1("good"));
621}
622
623void tst_qqmlpropertycache::derivedGadgetMethod()
624{
625 qmlRegisterTypesAndRevisions<BaseGadget, DerivedGadget, GadgetUser>(uri: "Test.PropertyCache", versionMajor: 1);
626 QQmlEngine engine;
627 QQmlComponent c(&engine, testFileUrl(fileName: "derivedGadgetMethod.qml"));
628 QVERIFY(c.isReady());
629 QScopedPointer<QObject> obj(c.create());
630 QVERIFY(!obj.isNull());
631 GadgetUser *gadgetUser = qobject_cast<GadgetUser *>(object: obj.data());
632 QVERIFY(gadgetUser);
633 QCOMPARE(gadgetUser->baseString(), QString::fromLatin1("base"));
634 QCOMPARE(gadgetUser->derivedString(), QString::fromLatin1("derived"));
635}
636
637QTEST_MAIN(tst_qqmlpropertycache)
638

source code of qtdeclarative/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp