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 | |
38 | class tst_qqmlpropertycache : public QQmlDataTest |
39 | { |
40 | Q_OBJECT |
41 | public: |
42 | tst_qqmlpropertycache() {} |
43 | |
44 | private 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 | |
60 | private: |
61 | QQmlEngine engine; |
62 | }; |
63 | |
64 | class BaseGadget |
65 | { |
66 | Q_GADGET |
67 | QML_ANONYMOUS |
68 | public: |
69 | Q_INVOKABLE QString stringValue() { return QLatin1String("base" ); } |
70 | }; |
71 | |
72 | Q_DECLARE_METATYPE(BaseGadget) |
73 | |
74 | class DerivedGadget : public BaseGadget |
75 | { |
76 | Q_GADGET |
77 | QML_ANONYMOUS |
78 | public: |
79 | Q_INVOKABLE QString stringValue() { return QLatin1String("derived" ); } |
80 | }; |
81 | |
82 | Q_DECLARE_METATYPE(DerivedGadget) |
83 | |
84 | class 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 | |
93 | public: |
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 | |
99 | public 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 | |
118 | signals: |
119 | void baseStringChanged(QString baseString); |
120 | void derivedStringChanged(QString derivedString); |
121 | |
122 | private: |
123 | BaseGadget m_base; |
124 | DerivedGadget m_derived; |
125 | QString m_baseString; |
126 | QString m_derivedString; |
127 | }; |
128 | |
129 | class 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) |
134 | public: |
135 | BaseObject(QObject *parent = nullptr) : QObject(parent) {} |
136 | |
137 | int propertyA() const { return 0; } |
138 | QString propertyB() const { return QString(); } |
139 | |
140 | public Q_SLOTS: |
141 | void slotA() {} |
142 | |
143 | Q_SIGNALS: |
144 | void propertyAChanged(); |
145 | void propertyBChanged(); |
146 | void signalA(); |
147 | }; |
148 | |
149 | class 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) |
155 | public: |
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 | |
162 | public Q_SLOTS: |
163 | void slotB() {} |
164 | |
165 | Q_SIGNALS: |
166 | void propertyCChanged(); |
167 | void propertyDChanged(); |
168 | Q_REVISION(1) void propertyEChanged(); |
169 | void signalB(); |
170 | }; |
171 | |
172 | QQmlPropertyData *cacheProperty(const QQmlRefPointer<QQmlPropertyCache> &cache, const char *name) |
173 | { |
174 | return cache->property(key: QLatin1String(name), object: nullptr, context: nullptr); |
175 | } |
176 | |
177 | void 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 | |
199 | void 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 | |
222 | void 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 | |
239 | void 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 | |
273 | void 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 | |
308 | void 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 | |
336 | void 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 | |
365 | class 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 | |
390 | class 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) |
395 | public: |
396 | MyEnum::Option1 opt1() const { return m_opt1; } |
397 | MyEnum::ShortEnum opt2() const { return m_opt2; } |
398 | |
399 | signals: |
400 | void opt1Changed(MyEnum::Option1 opt1); |
401 | void opt2Changed(MyEnum::ShortEnum opt2); |
402 | |
403 | public 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 | |
425 | private: |
426 | MyEnum::Option1 m_opt1 = MyEnum::Option10; |
427 | MyEnum::ShortEnum m_opt2 = MyEnum::Short8; |
428 | }; |
429 | |
430 | void 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 | |
450 | Q_DECLARE_METATYPE(MyEnum::Option1) |
451 | Q_DECLARE_METATYPE(MyEnum::ShortEnum) |
452 | |
453 | QT_BEGIN_NAMESPACE |
454 | class SimpleGadget |
455 | { |
456 | Q_GADGET |
457 | Q_PROPERTY(bool someProperty READ someProperty) |
458 | public: |
459 | bool someProperty() const { return true; } |
460 | }; |
461 | |
462 | // Avoids NeedsCreation and NeedsDestruction flags |
463 | Q_DECLARE_TYPEINFO(SimpleGadget, Q_PRIMITIVE_TYPE); |
464 | QT_END_NAMESPACE |
465 | |
466 | class GadgetEmitter : public QObject |
467 | { |
468 | Q_OBJECT |
469 | signals: |
470 | void emitGadget(SimpleGadget); |
471 | }; |
472 | |
473 | void 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 | |
491 | class TestClass : public QObject |
492 | { |
493 | Q_OBJECT |
494 | Q_PROPERTY(int prop READ prop WRITE setProp NOTIFY propChanged) |
495 | int m_prop; |
496 | |
497 | public: |
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 | |
512 | public slots: |
513 | void setProp(int prop) |
514 | { |
515 | if (m_prop == prop) |
516 | return; |
517 | |
518 | m_prop = prop; |
519 | emit propChanged(prop); |
520 | } |
521 | signals: |
522 | void propChanged(int prop); |
523 | }; |
524 | |
525 | class TestClassWithParameters : public QObject |
526 | { |
527 | Q_OBJECT |
528 | |
529 | public: |
530 | Q_INVOKABLE void slotWithArguments(int firstArg) { |
531 | Q_UNUSED(firstArg); |
532 | } |
533 | }; |
534 | |
535 | class 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 | |
549 | Q_DECLARE_METATYPE(const QMetaObject*); |
550 | |
551 | void 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 | |
562 | void 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 | |
577 | void 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 | |
613 | void 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 | |
623 | void 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 | |
637 | QTEST_MAIN(tst_qqmlpropertycache) |
638 | |