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 "interfaces.h" |
30 | #include <qtest.h> |
31 | #include <QtQml/qqmlengine.h> |
32 | #include <QtQml/qqmlcomponent.h> |
33 | #include <QtQml/qqmlcontext.h> |
34 | #include <QtQml/qqmlproperty.h> |
35 | #include <QtQml/private/qqmlproperty_p.h> |
36 | #include <private/qqmlbinding_p.h> |
37 | #include <private/qqmlboundsignal_p.h> |
38 | #include <QtCore/qfileinfo.h> |
39 | #include <QtCore/qdir.h> |
40 | #if QT_CONFIG(regularexpression) |
41 | #include <QtCore/qregularexpression.h> |
42 | #endif |
43 | #include <QtCore/private/qobject_p.h> |
44 | #include "../../shared/util.h" |
45 | #include "qobject.h" |
46 | #include <QtQml/QQmlPropertyMap> |
47 | |
48 | #include <QDebug> |
49 | class MyQmlObject : public QObject |
50 | { |
51 | Q_OBJECT |
52 | Q_PROPERTY(QPoint pointProperty MEMBER m_point) |
53 | public: |
54 | MyQmlObject(QObject *parent = nullptr) : QObject(parent) {} |
55 | |
56 | private: |
57 | QPoint m_point; |
58 | }; |
59 | |
60 | QML_DECLARE_TYPE(MyQmlObject); |
61 | |
62 | class MyQObject : public QObject |
63 | { |
64 | Q_OBJECT |
65 | public: |
66 | MyQObject(QObject *parent = nullptr) : QObject(parent), m_i(0) {} |
67 | |
68 | int inc() { return ++m_i; } |
69 | |
70 | private: |
71 | int m_i; |
72 | }; |
73 | |
74 | |
75 | class MyAttached : public QObject |
76 | { |
77 | Q_OBJECT |
78 | Q_PROPERTY(int foo READ foo WRITE setFoo) |
79 | public: |
80 | MyAttached(QObject *parent) : QObject(parent), m_foo(13) {} |
81 | |
82 | int foo() const { return m_foo; } |
83 | void setFoo(int f) { m_foo = f; } |
84 | |
85 | private: |
86 | int m_foo; |
87 | }; |
88 | |
89 | class MyContainer : public QObject |
90 | { |
91 | Q_OBJECT |
92 | Q_PROPERTY(QQmlListProperty<MyQmlObject> children READ children) |
93 | public: |
94 | MyContainer() {} |
95 | |
96 | QQmlListProperty<MyQmlObject> children() { return QQmlListProperty<MyQmlObject>(this, m_children); } |
97 | |
98 | static MyAttached *qmlAttachedProperties(QObject *o) { |
99 | return new MyAttached(o); |
100 | } |
101 | |
102 | private: |
103 | QList<MyQmlObject*> m_children; |
104 | }; |
105 | |
106 | QML_DECLARE_TYPE(MyContainer); |
107 | QML_DECLARE_TYPEINFO(MyContainer, QML_HAS_ATTACHED_PROPERTIES) |
108 | |
109 | class tst_qqmlproperty : public QQmlDataTest |
110 | { |
111 | Q_OBJECT |
112 | public: |
113 | tst_qqmlproperty() {} |
114 | |
115 | private slots: |
116 | void initTestCase(); |
117 | |
118 | // Constructors |
119 | void qmlmetaproperty(); |
120 | void qmlmetaproperty_object(); |
121 | void qmlmetaproperty_object_string(); |
122 | void qmlmetaproperty_object_context(); |
123 | void qmlmetaproperty_object_string_context(); |
124 | |
125 | // Methods |
126 | void name(); |
127 | void read(); |
128 | void write(); |
129 | void reset(); |
130 | |
131 | // Functionality |
132 | void writeObjectToList(); |
133 | void writeListToList(); |
134 | |
135 | //writeToReadOnly(); |
136 | |
137 | void urlHandling_data(); |
138 | void urlHandling(); |
139 | |
140 | void variantMapHandling_data(); |
141 | void variantMapHandling(); |
142 | |
143 | // Bugs |
144 | void crashOnValueProperty(); |
145 | void aliasPropertyBindings_data(); |
146 | void aliasPropertyBindings(); |
147 | void noContext(); |
148 | void assignEmptyVariantMap(); |
149 | void warnOnInvalidBinding(); |
150 | void registeredCompositeTypeProperty(); |
151 | void deeplyNestedObject(); |
152 | void readOnlyDynamicProperties(); |
153 | void aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSystem(); |
154 | void nullPropertyBinding(); |
155 | void interfaceBinding(); |
156 | |
157 | void floatToStringPrecision_data(); |
158 | void floatToStringPrecision(); |
159 | |
160 | void copy(); |
161 | |
162 | void bindingToAlias(); |
163 | |
164 | void nestedQQmlPropertyMap(); |
165 | |
166 | void underscorePropertyChangeHandler(); |
167 | |
168 | void signalExpressionWithoutObject(); |
169 | private: |
170 | QQmlEngine engine; |
171 | }; |
172 | |
173 | void tst_qqmlproperty::qmlmetaproperty() |
174 | { |
175 | QQmlProperty prop; |
176 | |
177 | QObject *obj = new QObject; |
178 | |
179 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(nullptr, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
180 | QVERIFY(binding); |
181 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(obj, QObjectPrivate::get(o: obj)->signalIndex(signalName: "destroyed()" ), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
182 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
183 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
184 | |
185 | QCOMPARE(prop.name(), QString()); |
186 | QCOMPARE(prop.read(), QVariant()); |
187 | QCOMPARE(prop.write(QVariant()), false); |
188 | QCOMPARE(prop.hasNotifySignal(), false); |
189 | QCOMPARE(prop.needsNotifySignal(), false); |
190 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
191 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
192 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
193 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
194 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
195 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
196 | QVERIFY(!prop.method().isValid()); |
197 | QCOMPARE(prop.type(), QQmlProperty::Invalid); |
198 | QCOMPARE(prop.isProperty(), false); |
199 | QCOMPARE(prop.isWritable(), false); |
200 | QCOMPARE(prop.isDesignable(), false); |
201 | QCOMPARE(prop.isResettable(), false); |
202 | QCOMPARE(prop.isSignalProperty(), false); |
203 | QCOMPARE(prop.isValid(), false); |
204 | QCOMPARE(prop.object(), (QObject *)nullptr); |
205 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory); |
206 | QCOMPARE(prop.propertyType(), 0); |
207 | QCOMPARE(prop.propertyTypeName(), (const char *)nullptr); |
208 | QVERIFY(!prop.property().name()); |
209 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
210 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
211 | QVERIFY(binding->ref == 1); |
212 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
213 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
214 | QVERIFY(sigExprWatcher.wasDeleted()); |
215 | QCOMPARE(prop.index(), -1); |
216 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
217 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
218 | |
219 | delete obj; |
220 | } |
221 | |
222 | // 1 = equal, 0 = unknown, -1 = not equal. |
223 | static int compareVariantAndListReference(const QVariant &v, QQmlListReference &r) |
224 | { |
225 | if (QLatin1String(v.typeName()) != QLatin1String("QQmlListReference" )) |
226 | return -1; |
227 | |
228 | QQmlListReference lhs = v.value<QQmlListReference>(); |
229 | if (lhs.isValid() != r.isValid()) |
230 | return -1; |
231 | |
232 | if (lhs.canCount() != r.canCount()) |
233 | return -1; |
234 | |
235 | if (!lhs.canCount()) { |
236 | if (lhs.canAt() != r.canAt()) |
237 | return -1; // not equal. |
238 | return 0; // not sure if they're equal or not, and no way to tell. |
239 | } |
240 | |
241 | // if we get here, we must be able to count. |
242 | if (lhs.count() != r.count()) |
243 | return -1; |
244 | |
245 | if (lhs.canAt() != r.canAt()) |
246 | return -1; |
247 | |
248 | if (!lhs.canAt()) |
249 | return 0; // can count, but can't check element equality. |
250 | |
251 | for (int i = 0; i < lhs.count(); ++i) { |
252 | if (lhs.at(i) != r.at(i)) { |
253 | return -1; // different elements :. not equal. |
254 | } |
255 | } |
256 | |
257 | return 1; // equal. |
258 | } |
259 | |
260 | void tst_qqmlproperty::registeredCompositeTypeProperty() |
261 | { |
262 | // Composite type properties |
263 | { |
264 | QQmlEngine engine; |
265 | QQmlComponent component(&engine, testFileUrl(fileName: "registeredCompositeTypeProperty.qml" )); |
266 | QObject *obj = component.create(); |
267 | QVERIFY(obj); |
268 | |
269 | // create property accessors and check types. |
270 | QQmlProperty p1(obj, "first" ); |
271 | QQmlProperty p2(obj, "second" ); |
272 | QQmlProperty p3(obj, "third" ); |
273 | QQmlProperty p1e(obj, "first" , &engine); |
274 | QQmlProperty p2e(obj, "second" , &engine); |
275 | QQmlProperty p3e(obj, "third" , &engine); |
276 | QCOMPARE(p1.propertyType(), p2.propertyType()); |
277 | QVERIFY(p1.propertyType() != p3.propertyType()); |
278 | |
279 | // check that the values are retrievable from CPP |
280 | QVariant first = obj->property(name: "first" ); |
281 | QVariant second = obj->property(name: "second" ); |
282 | QVariant third = obj->property(name: "third" ); |
283 | QVERIFY(first.isValid()); |
284 | QVERIFY(second.isValid()); |
285 | QVERIFY(third.isValid()); |
286 | // ensure that conversion from qobject-derived-ptr to qobject-ptr works. |
287 | QVERIFY(first.value<QObject*>()); |
288 | QVERIFY(second.value<QObject*>()); |
289 | QVERIFY(third.value<QObject*>()); |
290 | |
291 | // check that the values retrieved via QQmlProperty match those retrieved via QMetaProperty::read(). |
292 | QCOMPARE(p1.read().value<QObject*>(), first.value<QObject*>()); |
293 | QCOMPARE(p2.read().value<QObject*>(), second.value<QObject*>()); |
294 | QCOMPARE(p3.read().value<QObject*>(), third.value<QObject*>()); |
295 | QCOMPARE(p1e.read().value<QObject*>(), first.value<QObject*>()); |
296 | QCOMPARE(p2e.read().value<QObject*>(), second.value<QObject*>()); |
297 | QCOMPARE(p3e.read().value<QObject*>(), third.value<QObject*>()); |
298 | |
299 | delete obj; |
300 | } |
301 | |
302 | // List-of-composite-type type properties |
303 | { |
304 | QQmlEngine engine; |
305 | QQmlComponent component(&engine, testFileUrl(fileName: "registeredCompositeTypeProperty.qml" )); |
306 | QObject *obj = component.create(); |
307 | QVERIFY(obj); |
308 | |
309 | // create list property accessors and check types |
310 | QQmlProperty lp1e(obj, "fclist" , &engine); |
311 | QQmlProperty lp2e(obj, "sclistOne" , &engine); |
312 | QQmlProperty lp3e(obj, "sclistTwo" , &engine); |
313 | QVERIFY(lp1e.propertyType() != lp2e.propertyType()); |
314 | QCOMPARE(lp2e.propertyType(), lp3e.propertyType()); |
315 | |
316 | // check that the list values are retrievable from CPP |
317 | QVariant firstList = obj->property(name: "fclist" ); |
318 | QVariant secondList = obj->property(name: "sclistOne" ); |
319 | QVariant thirdList = obj->property(name: "sclistTwo" ); |
320 | QVERIFY(firstList.isValid()); |
321 | QVERIFY(secondList.isValid()); |
322 | QVERIFY(thirdList.isValid()); |
323 | |
324 | // check that the value returned by QQmlProperty::read() is equivalent to the list reference. |
325 | QQmlListReference r1(obj, "fclist" , &engine); |
326 | QQmlListReference r2(obj, "sclistOne" , &engine); |
327 | QQmlListReference r3(obj, "sclistTwo" , &engine); |
328 | QCOMPARE(compareVariantAndListReference(lp1e.read(), r1), 1); |
329 | QCOMPARE(compareVariantAndListReference(lp2e.read(), r2), 1); |
330 | QCOMPARE(compareVariantAndListReference(lp3e.read(), r3), 1); |
331 | |
332 | delete obj; |
333 | } |
334 | } |
335 | |
336 | class PropertyObject : public QObject |
337 | { |
338 | Q_OBJECT |
339 | Q_PROPERTY(int defaultProperty READ defaultProperty) |
340 | Q_PROPERTY(QRect rectProperty READ rectProperty) |
341 | Q_PROPERTY(QRect wrectProperty READ wrectProperty WRITE setWRectProperty) |
342 | Q_PROPERTY(QUrl url READ url WRITE setUrl) |
343 | Q_PROPERTY(QVariantMap variantMap READ variantMap WRITE setVariantMap) |
344 | Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty) |
345 | Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal) |
346 | Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject) |
347 | Q_PROPERTY(MyQObject *qObject READ qObject WRITE setQObject NOTIFY qObjectChanged) |
348 | Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) |
349 | Q_PROPERTY(QChar qcharProperty READ qcharProperty WRITE setQcharProperty) |
350 | Q_PROPERTY(QChar constQChar READ constQChar STORED false CONSTANT FINAL) |
351 | |
352 | Q_CLASSINFO("DefaultProperty" , "defaultProperty" ) |
353 | public: |
354 | PropertyObject() : m_resetProperty(9), m_qObject(nullptr), m_stringProperty("foo" ) {} |
355 | |
356 | int defaultProperty() { return 10; } |
357 | QRect rectProperty() { return QRect(10, 10, 1, 209); } |
358 | |
359 | QRect wrectProperty() { return m_rect; } |
360 | void setWRectProperty(const QRect &r) { m_rect = r; } |
361 | |
362 | QUrl url() { return m_url; } |
363 | void setUrl(const QUrl &u) { m_url = u; } |
364 | |
365 | QVariantMap variantMap() const { return m_variantMap; } |
366 | void setVariantMap(const QVariantMap &variantMap) { m_variantMap = variantMap; } |
367 | |
368 | int resettableProperty() const { return m_resetProperty; } |
369 | void setResettableProperty(int r) { m_resetProperty = r; } |
370 | void resetProperty() { m_resetProperty = 9; } |
371 | |
372 | int propertyWithNotify() const { return m_propertyWithNotify; } |
373 | void setPropertyWithNotify(int i) { m_propertyWithNotify = i; emit oddlyNamedNotifySignal(); } |
374 | |
375 | MyQmlObject *qmlObject() { return &m_qmlObject; } |
376 | |
377 | MyQObject *qObject() { return m_qObject; } |
378 | void setQObject(MyQObject *object) |
379 | { |
380 | if (m_qObject != object) { |
381 | m_qObject = object; |
382 | emit qObjectChanged(); |
383 | } |
384 | } |
385 | |
386 | QString stringProperty() const { return m_stringProperty;} |
387 | QChar qcharProperty() const { return m_qcharProperty; } |
388 | |
389 | QChar constQChar() const { return 0x25cf; /* Unicode: black circle */ } |
390 | |
391 | void setStringProperty(QString arg) { m_stringProperty = arg; } |
392 | void setQcharProperty(QChar arg) { m_qcharProperty = arg; } |
393 | |
394 | signals: |
395 | void clicked(); |
396 | void oddlyNamedNotifySignal(); |
397 | void qObjectChanged(); |
398 | |
399 | private: |
400 | int m_resetProperty; |
401 | QRect m_rect; |
402 | QUrl m_url; |
403 | QVariantMap m_variantMap; |
404 | int m_propertyWithNotify; |
405 | MyQmlObject m_qmlObject; |
406 | MyQObject *m_qObject; |
407 | QString m_stringProperty; |
408 | QChar m_qcharProperty; |
409 | }; |
410 | |
411 | QML_DECLARE_TYPE(PropertyObject); |
412 | |
413 | void tst_qqmlproperty::qmlmetaproperty_object() |
414 | { |
415 | QObject object; // Has no default property |
416 | PropertyObject dobject; // Has default property |
417 | |
418 | { |
419 | QQmlProperty prop(&object); |
420 | |
421 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
422 | QVERIFY(binding); |
423 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(o: &object)->signalIndex(signalName: "destroyed()" ), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
424 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
425 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
426 | |
427 | QObject *obj = new QObject; |
428 | |
429 | QCOMPARE(prop.name(), QString()); |
430 | QCOMPARE(prop.read(), QVariant()); |
431 | QCOMPARE(prop.write(QVariant()), false); |
432 | QCOMPARE(prop.hasNotifySignal(), false); |
433 | QCOMPARE(prop.needsNotifySignal(), false); |
434 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
435 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
436 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
437 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
438 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
439 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
440 | QVERIFY(!prop.method().isValid()); |
441 | QCOMPARE(prop.type(), QQmlProperty::Invalid); |
442 | QCOMPARE(prop.isProperty(), false); |
443 | QCOMPARE(prop.isWritable(), false); |
444 | QCOMPARE(prop.isDesignable(), false); |
445 | QCOMPARE(prop.isResettable(), false); |
446 | QCOMPARE(prop.isSignalProperty(), false); |
447 | QCOMPARE(prop.isValid(), false); |
448 | QCOMPARE(prop.object(), (QObject *)nullptr); |
449 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory); |
450 | QCOMPARE(prop.propertyType(), 0); |
451 | QCOMPARE(prop.propertyTypeName(), (const char *)nullptr); |
452 | QVERIFY(!prop.property().name()); |
453 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
454 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
455 | QVERIFY(binding->ref == 1); |
456 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
457 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
458 | QVERIFY(sigExprWatcher.wasDeleted()); |
459 | QCOMPARE(prop.index(), -1); |
460 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
461 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
462 | |
463 | delete obj; |
464 | } |
465 | |
466 | { |
467 | QQmlProperty prop(&dobject); |
468 | |
469 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
470 | static_cast<QQmlBinding *>(binding.data())->setTarget(prop); |
471 | QVERIFY(binding); |
472 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(o: &dobject)->signalIndex(signalName: "clicked()" ), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
473 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
474 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
475 | |
476 | QObject *obj = new QObject; |
477 | |
478 | QCOMPARE(prop.name(), QString("defaultProperty" )); |
479 | QCOMPARE(prop.read(), QVariant(10)); |
480 | QCOMPARE(prop.write(QVariant()), false); |
481 | QCOMPARE(prop.hasNotifySignal(), false); |
482 | QCOMPARE(prop.needsNotifySignal(), true); |
483 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
484 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
485 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
486 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
487 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
488 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
489 | QVERIFY(!prop.method().isValid()); |
490 | QCOMPARE(prop.type(), QQmlProperty::Property); |
491 | QCOMPARE(prop.isProperty(), true); |
492 | QCOMPARE(prop.isWritable(), false); |
493 | QCOMPARE(prop.isDesignable(), true); |
494 | QCOMPARE(prop.isResettable(), false); |
495 | QCOMPARE(prop.isSignalProperty(), false); |
496 | QCOMPARE(prop.isValid(), true); |
497 | QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject)); |
498 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::Normal); |
499 | QCOMPARE(prop.propertyType(), (int)QVariant::Int); |
500 | QCOMPARE(prop.propertyTypeName(), "int" ); |
501 | QCOMPARE(QString(prop.property().name()), QString("defaultProperty" )); |
502 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
503 | QTest::ignoreMessage(type: QtWarningMsg, message: "<Unknown File>: Unable to assign null to int" ); |
504 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
505 | QVERIFY(binding); |
506 | QCOMPARE(QQmlPropertyPrivate::binding(prop), binding.data()); |
507 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
508 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
509 | QVERIFY(sigExprWatcher.wasDeleted()); |
510 | QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty" )); |
511 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
512 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
513 | |
514 | delete obj; |
515 | } |
516 | } |
517 | |
518 | void tst_qqmlproperty::qmlmetaproperty_object_string() |
519 | { |
520 | QObject object; |
521 | PropertyObject dobject; |
522 | |
523 | { |
524 | QQmlProperty prop(&object, QString("defaultProperty" )); |
525 | |
526 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
527 | QVERIFY(binding); |
528 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(o: &object)->signalIndex(signalName: "destroyed()" ), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
529 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
530 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
531 | |
532 | QObject *obj = new QObject; |
533 | |
534 | QCOMPARE(prop.name(), QString()); |
535 | QCOMPARE(prop.read(), QVariant()); |
536 | QCOMPARE(prop.write(QVariant()), false); |
537 | QCOMPARE(prop.hasNotifySignal(), false); |
538 | QCOMPARE(prop.needsNotifySignal(), false); |
539 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
540 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
541 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
542 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
543 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
544 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
545 | QVERIFY(!prop.method().isValid()); |
546 | QCOMPARE(prop.type(), QQmlProperty::Invalid); |
547 | QCOMPARE(prop.isProperty(), false); |
548 | QCOMPARE(prop.isWritable(), false); |
549 | QCOMPARE(prop.isDesignable(), false); |
550 | QCOMPARE(prop.isResettable(), false); |
551 | QCOMPARE(prop.isSignalProperty(), false); |
552 | QCOMPARE(prop.isValid(), false); |
553 | QCOMPARE(prop.object(), (QObject *)nullptr); |
554 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory); |
555 | QCOMPARE(prop.propertyType(), 0); |
556 | QCOMPARE(prop.propertyTypeName(), (const char *)nullptr); |
557 | QVERIFY(!prop.property().name()); |
558 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
559 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
560 | QVERIFY(binding->ref == 1); |
561 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
562 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
563 | QVERIFY(sigExprWatcher.wasDeleted()); |
564 | QCOMPARE(prop.index(), -1); |
565 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
566 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
567 | |
568 | delete obj; |
569 | } |
570 | |
571 | { |
572 | QQmlProperty prop(&dobject, QString("defaultProperty" )); |
573 | |
574 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
575 | static_cast<QQmlBinding *>(binding.data())->setTarget(prop); |
576 | QVERIFY(binding); |
577 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(o: &dobject)->signalIndex(signalName: "clicked()" ), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
578 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
579 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
580 | |
581 | QObject *obj = new QObject; |
582 | |
583 | QCOMPARE(prop.name(), QString("defaultProperty" )); |
584 | QCOMPARE(prop.read(), QVariant(10)); |
585 | QCOMPARE(prop.write(QVariant()), false); |
586 | QCOMPARE(prop.hasNotifySignal(), false); |
587 | QCOMPARE(prop.needsNotifySignal(), true); |
588 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
589 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
590 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
591 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
592 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
593 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
594 | QVERIFY(!prop.method().isValid()); |
595 | QCOMPARE(prop.type(), QQmlProperty::Property); |
596 | QCOMPARE(prop.isProperty(), true); |
597 | QCOMPARE(prop.isWritable(), false); |
598 | QCOMPARE(prop.isDesignable(), true); |
599 | QCOMPARE(prop.isResettable(), false); |
600 | QCOMPARE(prop.isSignalProperty(), false); |
601 | QCOMPARE(prop.isValid(), true); |
602 | QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject)); |
603 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::Normal); |
604 | QCOMPARE(prop.propertyType(), (int)QVariant::Int); |
605 | QCOMPARE(prop.propertyTypeName(), "int" ); |
606 | QCOMPARE(QString(prop.property().name()), QString("defaultProperty" )); |
607 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
608 | QTest::ignoreMessage(type: QtWarningMsg, message: "<Unknown File>: Unable to assign null to int" ); |
609 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
610 | QVERIFY(binding); |
611 | QCOMPARE(QQmlPropertyPrivate::binding(prop), binding.data()); |
612 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
613 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
614 | QVERIFY(sigExprWatcher.wasDeleted()); |
615 | QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty" )); |
616 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
617 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
618 | |
619 | delete obj; |
620 | } |
621 | |
622 | { |
623 | QQmlProperty prop(&dobject, QString("onClicked" )); |
624 | |
625 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
626 | static_cast<QQmlBinding *>(binding.data())->setTarget(prop); |
627 | QVERIFY(binding); |
628 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(p: prop)->signalIndex(), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
629 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
630 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
631 | |
632 | QObject *obj = new QObject; |
633 | |
634 | QCOMPARE(prop.name(), QString("onClicked" )); |
635 | QCOMPARE(prop.read(), QVariant()); |
636 | QCOMPARE(prop.write(QVariant("Hello" )), false); |
637 | QCOMPARE(prop.hasNotifySignal(), false); |
638 | QCOMPARE(prop.needsNotifySignal(), false); |
639 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
640 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
641 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
642 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
643 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
644 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
645 | QCOMPARE(QString(prop.method().methodSignature()), QString("clicked()" )); |
646 | QCOMPARE(prop.type(), QQmlProperty::SignalProperty); |
647 | QCOMPARE(prop.isProperty(), false); |
648 | QCOMPARE(prop.isWritable(), false); |
649 | QCOMPARE(prop.isDesignable(), false); |
650 | QCOMPARE(prop.isResettable(), false); |
651 | QCOMPARE(prop.isSignalProperty(), true); |
652 | QCOMPARE(prop.isValid(), true); |
653 | QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject)); |
654 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory); |
655 | QCOMPARE(prop.propertyType(), 0); |
656 | QCOMPARE(prop.propertyTypeName(), (const char *)nullptr); |
657 | QCOMPARE(prop.property().name(), (const char *)nullptr); |
658 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
659 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
660 | QVERIFY(binding->ref == 1); |
661 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
662 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
663 | QVERIFY(!sigExprWatcher.wasDeleted()); |
664 | QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); |
665 | QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()" )); |
666 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
667 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
668 | |
669 | delete obj; |
670 | } |
671 | |
672 | { |
673 | QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged" )); |
674 | |
675 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
676 | static_cast<QQmlBinding *>(binding.data())->setTarget(prop); |
677 | QVERIFY(binding); |
678 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(p: prop)->signalIndex(), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
679 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
680 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
681 | |
682 | QObject *obj = new QObject; |
683 | |
684 | QCOMPARE(prop.name(), QString("onOddlyNamedNotifySignal" )); |
685 | QCOMPARE(prop.read(), QVariant()); |
686 | QCOMPARE(prop.write(QVariant("Hello" )), false); |
687 | QCOMPARE(prop.hasNotifySignal(), false); |
688 | QCOMPARE(prop.needsNotifySignal(), false); |
689 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
690 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
691 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
692 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
693 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
694 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
695 | QCOMPARE(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()" )); |
696 | QCOMPARE(prop.type(), QQmlProperty::SignalProperty); |
697 | QCOMPARE(prop.isProperty(), false); |
698 | QCOMPARE(prop.isWritable(), false); |
699 | QCOMPARE(prop.isDesignable(), false); |
700 | QCOMPARE(prop.isResettable(), false); |
701 | QCOMPARE(prop.isSignalProperty(), true); |
702 | QCOMPARE(prop.isValid(), true); |
703 | QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject)); |
704 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory); |
705 | QCOMPARE(prop.propertyType(), 0); |
706 | QCOMPARE(prop.propertyTypeName(), (const char *)nullptr); |
707 | QCOMPARE(prop.property().name(), (const char *)nullptr); |
708 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
709 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
710 | QVERIFY(binding->ref == 1); |
711 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
712 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
713 | QVERIFY(!sigExprWatcher.wasDeleted()); |
714 | QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); |
715 | QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()" )); |
716 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
717 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
718 | |
719 | delete obj; |
720 | } |
721 | } |
722 | |
723 | void tst_qqmlproperty::qmlmetaproperty_object_context() |
724 | { |
725 | QObject object; // Has no default property |
726 | PropertyObject dobject; // Has default property |
727 | |
728 | { |
729 | QQmlProperty prop(&object, engine.rootContext()); |
730 | |
731 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
732 | QVERIFY(binding); |
733 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(o: &object)->signalIndex(signalName: "destroyed()" ), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
734 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
735 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
736 | |
737 | QObject *obj = new QObject; |
738 | |
739 | QCOMPARE(prop.name(), QString()); |
740 | QCOMPARE(prop.read(), QVariant()); |
741 | QCOMPARE(prop.write(QVariant()), false); |
742 | QCOMPARE(prop.hasNotifySignal(), false); |
743 | QCOMPARE(prop.needsNotifySignal(), false); |
744 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
745 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
746 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
747 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
748 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
749 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
750 | QVERIFY(!prop.method().isValid()); |
751 | QCOMPARE(prop.type(), QQmlProperty::Invalid); |
752 | QCOMPARE(prop.isProperty(), false); |
753 | QCOMPARE(prop.isWritable(), false); |
754 | QCOMPARE(prop.isDesignable(), false); |
755 | QCOMPARE(prop.isResettable(), false); |
756 | QCOMPARE(prop.isSignalProperty(), false); |
757 | QCOMPARE(prop.isValid(), false); |
758 | QCOMPARE(prop.object(), (QObject *)nullptr); |
759 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory); |
760 | QCOMPARE(prop.propertyType(), 0); |
761 | QCOMPARE(prop.propertyTypeName(), (const char *)nullptr); |
762 | QVERIFY(!prop.property().name()); |
763 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
764 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
765 | QVERIFY(binding->ref == 1); |
766 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
767 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
768 | QVERIFY(sigExprWatcher.wasDeleted()); |
769 | QCOMPARE(prop.index(), -1); |
770 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
771 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
772 | |
773 | delete obj; |
774 | } |
775 | |
776 | { |
777 | QQmlProperty prop(&dobject, engine.rootContext()); |
778 | |
779 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
780 | static_cast<QQmlBinding *>(binding.data())->setTarget(prop); |
781 | QVERIFY(binding); |
782 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(o: &dobject)->signalIndex(signalName: "clicked()" ), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
783 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
784 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
785 | |
786 | QObject *obj = new QObject; |
787 | |
788 | QCOMPARE(prop.name(), QString("defaultProperty" )); |
789 | QCOMPARE(prop.read(), QVariant(10)); |
790 | QCOMPARE(prop.write(QVariant()), false); |
791 | QCOMPARE(prop.hasNotifySignal(), false); |
792 | QCOMPARE(prop.needsNotifySignal(), true); |
793 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
794 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
795 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
796 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
797 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
798 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
799 | QVERIFY(!prop.method().isValid()); |
800 | QCOMPARE(prop.type(), QQmlProperty::Property); |
801 | QCOMPARE(prop.isProperty(), true); |
802 | QCOMPARE(prop.isWritable(), false); |
803 | QCOMPARE(prop.isDesignable(), true); |
804 | QCOMPARE(prop.isResettable(), false); |
805 | QCOMPARE(prop.isSignalProperty(), false); |
806 | QCOMPARE(prop.isValid(), true); |
807 | QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject)); |
808 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::Normal); |
809 | QCOMPARE(prop.propertyType(), (int)QVariant::Int); |
810 | QCOMPARE(prop.propertyTypeName(), "int" ); |
811 | QCOMPARE(QString(prop.property().name()), QString("defaultProperty" )); |
812 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
813 | QTest::ignoreMessage(type: QtWarningMsg, message: "<Unknown File>: Unable to assign null to int" ); |
814 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
815 | QVERIFY(binding); |
816 | QCOMPARE(QQmlPropertyPrivate::binding(prop), binding.data()); |
817 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
818 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
819 | QVERIFY(sigExprWatcher.wasDeleted()); |
820 | QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty" )); |
821 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
822 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
823 | |
824 | delete obj; |
825 | } |
826 | } |
827 | |
828 | void tst_qqmlproperty::qmlmetaproperty_object_string_context() |
829 | { |
830 | QObject object; |
831 | PropertyObject dobject; |
832 | |
833 | { |
834 | QQmlProperty prop(&object, QString("defaultProperty" ), engine.rootContext()); |
835 | |
836 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
837 | QVERIFY(binding); |
838 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(o: &object)->signalIndex(signalName: "destroyed()" ), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
839 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
840 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
841 | |
842 | QObject *obj = new QObject; |
843 | |
844 | QCOMPARE(prop.name(), QString()); |
845 | QCOMPARE(prop.read(), QVariant()); |
846 | QCOMPARE(prop.write(QVariant()), false); |
847 | QCOMPARE(prop.hasNotifySignal(), false); |
848 | QCOMPARE(prop.needsNotifySignal(), false); |
849 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
850 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
851 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
852 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
853 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
854 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
855 | QVERIFY(!prop.method().isValid()); |
856 | QCOMPARE(prop.type(), QQmlProperty::Invalid); |
857 | QCOMPARE(prop.isProperty(), false); |
858 | QCOMPARE(prop.isWritable(), false); |
859 | QCOMPARE(prop.isDesignable(), false); |
860 | QCOMPARE(prop.isResettable(), false); |
861 | QCOMPARE(prop.isSignalProperty(), false); |
862 | QCOMPARE(prop.isValid(), false); |
863 | QCOMPARE(prop.object(), (QObject *)nullptr); |
864 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory); |
865 | QCOMPARE(prop.propertyType(), 0); |
866 | QCOMPARE(prop.propertyTypeName(), (const char *)nullptr); |
867 | QVERIFY(!prop.property().name()); |
868 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
869 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
870 | QVERIFY(binding->ref == 1); |
871 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
872 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
873 | QVERIFY(sigExprWatcher.wasDeleted()); |
874 | QCOMPARE(prop.index(), -1); |
875 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
876 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
877 | |
878 | delete obj; |
879 | } |
880 | |
881 | { |
882 | QQmlProperty prop(&dobject, QString("defaultProperty" ), engine.rootContext()); |
883 | |
884 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
885 | static_cast<QQmlBinding *>(binding.data())->setTarget(prop); |
886 | QVERIFY(binding); |
887 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(o: &dobject)->signalIndex(signalName: "clicked()" ), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
888 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
889 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
890 | |
891 | QObject *obj = new QObject; |
892 | |
893 | QCOMPARE(prop.name(), QString("defaultProperty" )); |
894 | QCOMPARE(prop.read(), QVariant(10)); |
895 | QCOMPARE(prop.write(QVariant()), false); |
896 | QCOMPARE(prop.hasNotifySignal(), false); |
897 | QCOMPARE(prop.needsNotifySignal(), true); |
898 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
899 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
900 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
901 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
902 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
903 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
904 | QVERIFY(!prop.method().isValid()); |
905 | QCOMPARE(prop.type(), QQmlProperty::Property); |
906 | QCOMPARE(prop.isProperty(), true); |
907 | QCOMPARE(prop.isWritable(), false); |
908 | QCOMPARE(prop.isDesignable(), true); |
909 | QCOMPARE(prop.isResettable(), false); |
910 | QCOMPARE(prop.isSignalProperty(), false); |
911 | QCOMPARE(prop.isValid(), true); |
912 | QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject)); |
913 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::Normal); |
914 | QCOMPARE(prop.propertyType(), (int)QVariant::Int); |
915 | QCOMPARE(prop.propertyTypeName(), "int" ); |
916 | QCOMPARE(QString(prop.property().name()), QString("defaultProperty" )); |
917 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
918 | QTest::ignoreMessage(type: QtWarningMsg, message: "<Unknown File>: Unable to assign null to int" ); |
919 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
920 | QVERIFY(binding); |
921 | QCOMPARE(QQmlPropertyPrivate::binding(prop), binding.data()); |
922 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
923 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
924 | QVERIFY(sigExprWatcher.wasDeleted()); |
925 | QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty" )); |
926 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
927 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
928 | |
929 | delete obj; |
930 | } |
931 | |
932 | { |
933 | QQmlProperty prop(&dobject, QString("onClicked" ), engine.rootContext()); |
934 | |
935 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
936 | static_cast<QQmlBinding *>(binding.data())->setTarget(prop); |
937 | QVERIFY(binding); |
938 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(p: prop)->signalIndex(), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
939 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
940 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
941 | |
942 | QObject *obj = new QObject; |
943 | |
944 | QCOMPARE(prop.name(), QString("onClicked" )); |
945 | QCOMPARE(prop.read(), QVariant()); |
946 | QCOMPARE(prop.write(QVariant("Hello" )), false); |
947 | QCOMPARE(prop.hasNotifySignal(), false); |
948 | QCOMPARE(prop.needsNotifySignal(), false); |
949 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
950 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
951 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
952 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
953 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
954 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
955 | QCOMPARE(QString(prop.method().methodSignature()), QString("clicked()" )); |
956 | QCOMPARE(prop.type(), QQmlProperty::SignalProperty); |
957 | QCOMPARE(prop.isProperty(), false); |
958 | QCOMPARE(prop.isWritable(), false); |
959 | QCOMPARE(prop.isDesignable(), false); |
960 | QCOMPARE(prop.isResettable(), false); |
961 | QCOMPARE(prop.isSignalProperty(), true); |
962 | QCOMPARE(prop.isValid(), true); |
963 | QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject)); |
964 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory); |
965 | QCOMPARE(prop.propertyType(), 0); |
966 | QCOMPARE(prop.propertyTypeName(), (const char *)nullptr); |
967 | QCOMPARE(prop.property().name(), (const char *)nullptr); |
968 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
969 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
970 | QVERIFY(binding->ref == 1); |
971 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
972 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
973 | QVERIFY(!sigExprWatcher.wasDeleted()); |
974 | QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); |
975 | QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()" )); |
976 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
977 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
978 | |
979 | delete obj; |
980 | } |
981 | |
982 | { |
983 | QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged" ), engine.rootContext()); |
984 | |
985 | QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(p: prop)->core, QLatin1String("null" ), nullptr, QQmlContextData::get(context: engine.rootContext()))); |
986 | static_cast<QQmlBinding *>(binding.data())->setTarget(prop); |
987 | QVERIFY(binding); |
988 | QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(p: prop)->signalIndex(), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1); |
989 | QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); |
990 | QVERIFY(sigExpr != nullptr && !sigExprWatcher.wasDeleted()); |
991 | |
992 | QObject *obj = new QObject; |
993 | |
994 | QCOMPARE(prop.name(), QString("onOddlyNamedNotifySignal" )); |
995 | QCOMPARE(prop.read(), QVariant()); |
996 | QCOMPARE(prop.write(QVariant("Hello" )), false); |
997 | QCOMPARE(prop.hasNotifySignal(), false); |
998 | QCOMPARE(prop.needsNotifySignal(), false); |
999 | QCOMPARE(prop.connectNotifySignal(nullptr, SLOT(deleteLater())), false); |
1000 | QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); |
1001 | QCOMPARE(prop.connectNotifySignal(obj, 0), false); |
1002 | QCOMPARE(prop.connectNotifySignal(nullptr, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
1003 | QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()" )), false); |
1004 | QCOMPARE(prop.connectNotifySignal(obj, -1), false); |
1005 | QCOMPARE(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()" )); |
1006 | QCOMPARE(prop.type(), QQmlProperty::SignalProperty); |
1007 | QCOMPARE(prop.isProperty(), false); |
1008 | QCOMPARE(prop.isWritable(), false); |
1009 | QCOMPARE(prop.isDesignable(), false); |
1010 | QCOMPARE(prop.isResettable(), false); |
1011 | QCOMPARE(prop.isSignalProperty(), true); |
1012 | QCOMPARE(prop.isValid(), true); |
1013 | QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject)); |
1014 | QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory); |
1015 | QCOMPARE(prop.propertyType(), 0); |
1016 | QCOMPARE(prop.propertyTypeName(), (const char *)nullptr); |
1017 | QCOMPARE(prop.property().name(), (const char *)nullptr); |
1018 | QVERIFY(!QQmlPropertyPrivate::binding(prop)); |
1019 | QQmlPropertyPrivate::setBinding(that: prop, binding.data()); |
1020 | QVERIFY(binding->ref == 1); |
1021 | QVERIFY(!QQmlPropertyPrivate::signalExpression(prop)); |
1022 | QQmlPropertyPrivate::takeSignalExpression(that: prop, sigExpr); |
1023 | QVERIFY(!sigExprWatcher.wasDeleted()); |
1024 | QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); |
1025 | QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()" )); |
1026 | QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); |
1027 | QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); |
1028 | |
1029 | delete obj; |
1030 | } |
1031 | } |
1032 | |
1033 | void tst_qqmlproperty::name() |
1034 | { |
1035 | { |
1036 | QQmlProperty p; |
1037 | QCOMPARE(p.name(), QString()); |
1038 | } |
1039 | |
1040 | { |
1041 | PropertyObject o; |
1042 | QQmlProperty p(&o); |
1043 | QCOMPARE(p.name(), QString("defaultProperty" )); |
1044 | } |
1045 | |
1046 | { |
1047 | QObject o; |
1048 | QQmlProperty p(&o, QString("objectName" )); |
1049 | QCOMPARE(p.name(), QString("objectName" )); |
1050 | } |
1051 | |
1052 | { |
1053 | PropertyObject o; |
1054 | QQmlProperty p(&o, "onClicked" ); |
1055 | QCOMPARE(p.name(), QString("onClicked" )); |
1056 | } |
1057 | |
1058 | { |
1059 | QObject o; |
1060 | QQmlProperty p(&o, "onClicked" ); |
1061 | QCOMPARE(p.name(), QString()); |
1062 | } |
1063 | |
1064 | { |
1065 | PropertyObject o; |
1066 | QQmlProperty p(&o, "onPropertyWithNotifyChanged" ); |
1067 | QCOMPARE(p.name(), QString("onOddlyNamedNotifySignal" )); |
1068 | } |
1069 | |
1070 | { |
1071 | QObject o; |
1072 | QQmlProperty p(&o, "onPropertyWithNotifyChanged" ); |
1073 | QCOMPARE(p.name(), QString()); |
1074 | } |
1075 | |
1076 | { |
1077 | QObject o; |
1078 | QQmlProperty p(&o, "foo" ); |
1079 | QCOMPARE(p.name(), QString()); |
1080 | } |
1081 | |
1082 | { |
1083 | QQmlProperty p(nullptr, "foo" ); |
1084 | QCOMPARE(p.name(), QString()); |
1085 | } |
1086 | |
1087 | { |
1088 | PropertyObject o; |
1089 | QQmlProperty p(&o, "rectProperty" ); |
1090 | QCOMPARE(p.name(), QString("rectProperty" )); |
1091 | } |
1092 | |
1093 | { |
1094 | PropertyObject o; |
1095 | QQmlProperty p(&o, "rectProperty.x" ); |
1096 | QCOMPARE(p.name(), QString("rectProperty.x" )); |
1097 | } |
1098 | |
1099 | { |
1100 | PropertyObject o; |
1101 | QQmlProperty p(&o, "rectProperty.foo" ); |
1102 | QCOMPARE(p.name(), QString()); |
1103 | } |
1104 | } |
1105 | |
1106 | void tst_qqmlproperty::read() |
1107 | { |
1108 | // Invalid |
1109 | { |
1110 | QQmlProperty p; |
1111 | QCOMPARE(p.read(), QVariant()); |
1112 | } |
1113 | |
1114 | // Default prop |
1115 | { |
1116 | PropertyObject o; |
1117 | QQmlProperty p(&o); |
1118 | QCOMPARE(p.read(), QVariant(10)); |
1119 | } |
1120 | |
1121 | // Invalid default prop |
1122 | { |
1123 | QObject o; |
1124 | QQmlProperty p(&o); |
1125 | QCOMPARE(p.read(), QVariant()); |
1126 | } |
1127 | |
1128 | // Value prop by name |
1129 | { |
1130 | QObject o; |
1131 | |
1132 | QQmlProperty p(&o, "objectName" ); |
1133 | QCOMPARE(p.read(), QVariant(QString())); |
1134 | |
1135 | o.setObjectName("myName" ); |
1136 | |
1137 | QCOMPARE(p.read(), QVariant("myName" )); |
1138 | } |
1139 | |
1140 | // Value prop by name (static) |
1141 | { |
1142 | QObject o; |
1143 | |
1144 | QCOMPARE(QQmlProperty::read(&o, "objectName" ), QVariant(QString())); |
1145 | |
1146 | o.setObjectName("myName" ); |
1147 | |
1148 | QCOMPARE(QQmlProperty::read(&o, "objectName" ), QVariant("myName" )); |
1149 | } |
1150 | |
1151 | // Value-type prop |
1152 | { |
1153 | PropertyObject o; |
1154 | QQmlProperty p(&o, "rectProperty.x" ); |
1155 | QCOMPARE(p.read(), QVariant(10)); |
1156 | } |
1157 | |
1158 | // Invalid value-type prop |
1159 | { |
1160 | PropertyObject o; |
1161 | QQmlProperty p(&o, "rectProperty.foo" ); |
1162 | QCOMPARE(p.read(), QVariant()); |
1163 | } |
1164 | |
1165 | // Signal property |
1166 | { |
1167 | PropertyObject o; |
1168 | QQmlProperty p(&o, "onClicked" ); |
1169 | QCOMPARE(p.read(), QVariant()); |
1170 | |
1171 | QQmlPropertyPrivate::takeSignalExpression(that: p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1)); |
1172 | QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p)); |
1173 | |
1174 | QCOMPARE(p.read(), QVariant()); |
1175 | } |
1176 | |
1177 | // Automatic signal property |
1178 | { |
1179 | PropertyObject o; |
1180 | QQmlProperty p(&o, "onPropertyWithNotifyChanged" ); |
1181 | QCOMPARE(p.read(), QVariant()); |
1182 | |
1183 | QQmlPropertyPrivate::takeSignalExpression(that: p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1)); |
1184 | QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p)); |
1185 | |
1186 | QCOMPARE(p.read(), QVariant()); |
1187 | } |
1188 | |
1189 | // Deleted object |
1190 | { |
1191 | PropertyObject *o = new PropertyObject; |
1192 | QQmlProperty p(o, "rectProperty.x" ); |
1193 | QCOMPARE(p.read(), QVariant(10)); |
1194 | delete o; |
1195 | QCOMPARE(p.read(), QVariant()); |
1196 | } |
1197 | |
1198 | // Object property registered with Qt, but not registered with QML. |
1199 | { |
1200 | PropertyObject o; |
1201 | QQmlProperty p(&o, "qObject" ); |
1202 | QCOMPARE(p.propertyTypeCategory(), QQmlProperty::Object); |
1203 | |
1204 | QCOMPARE(p.propertyType(), qMetaTypeId<MyQObject*>()); |
1205 | QVariant v = p.read(); |
1206 | QVERIFY(v.canConvert(QMetaType::QObjectStar)); |
1207 | QVERIFY(qvariant_cast<QObject *>(v) == o.qObject()); |
1208 | } |
1209 | { |
1210 | QQmlEngine engine; |
1211 | PropertyObject o; |
1212 | QQmlProperty p(&o, "qObject" , &engine); |
1213 | QCOMPARE(p.propertyTypeCategory(), QQmlProperty::Object); |
1214 | |
1215 | QCOMPARE(p.propertyType(), qMetaTypeId<MyQObject*>()); |
1216 | QVariant v = p.read(); |
1217 | QVERIFY(v.canConvert(QMetaType::QObjectStar)); |
1218 | QVERIFY(qvariant_cast<QObject *>(v) == o.qObject()); |
1219 | } |
1220 | |
1221 | // Object property |
1222 | { |
1223 | PropertyObject o; |
1224 | QQmlProperty p(&o, "qmlObject" ); |
1225 | QCOMPARE(p.propertyTypeCategory(), QQmlProperty::Object); |
1226 | QCOMPARE(p.propertyType(), qMetaTypeId<MyQmlObject*>()); |
1227 | QVariant v = p.read(); |
1228 | QCOMPARE(v.userType(), int(QMetaType::QObjectStar)); |
1229 | QVERIFY(qvariant_cast<QObject *>(v) == o.qmlObject()); |
1230 | } |
1231 | { |
1232 | QQmlComponent component(&engine, testFileUrl(fileName: "readSynthesizedObject.qml" )); |
1233 | QScopedPointer<QObject> object(component.create()); |
1234 | QVERIFY(object != nullptr); |
1235 | |
1236 | QQmlProperty p(object.data(), "test" , &engine); |
1237 | |
1238 | QCOMPARE(p.propertyTypeCategory(), QQmlProperty::Object); |
1239 | QVERIFY(p.propertyType() != QMetaType::QObjectStar); |
1240 | |
1241 | QVariant v = p.read(); |
1242 | QCOMPARE(v.userType(), int(QMetaType::QObjectStar)); |
1243 | QCOMPARE(qvariant_cast<QObject *>(v)->property("a" ).toInt(), 10); |
1244 | QCOMPARE(qvariant_cast<QObject *>(v)->property("b" ).toInt(), 19); |
1245 | } |
1246 | { // static |
1247 | QQmlComponent component(&engine, testFileUrl(fileName: "readSynthesizedObject.qml" )); |
1248 | QScopedPointer<QObject> object(component.create()); |
1249 | QVERIFY(object != nullptr); |
1250 | |
1251 | QVariant v = QQmlProperty::read(object.data(), "test" , &engine); |
1252 | QCOMPARE(v.userType(), int(QMetaType::QObjectStar)); |
1253 | QCOMPARE(qvariant_cast<QObject *>(v)->property("a" ).toInt(), 10); |
1254 | QCOMPARE(qvariant_cast<QObject *>(v)->property("b" ).toInt(), 19); |
1255 | } |
1256 | |
1257 | // Attached property |
1258 | { |
1259 | QQmlComponent component(&engine); |
1260 | component.setData("import Test 1.0\nMyContainer { }" , baseUrl: QUrl()); |
1261 | QScopedPointer<QObject> object(component.create()); |
1262 | QVERIFY(object != nullptr); |
1263 | |
1264 | QQmlProperty p(object.data(), "MyContainer.foo" , qmlContext(object.data())); |
1265 | QCOMPARE(p.read(), QVariant(13)); |
1266 | } |
1267 | { |
1268 | QQmlComponent component(&engine); |
1269 | component.setData("import Test 1.0\nMyContainer { MyContainer.foo: 10 }" , baseUrl: QUrl()); |
1270 | QScopedPointer<QObject> object(component.create()); |
1271 | QVERIFY(object != nullptr); |
1272 | |
1273 | QQmlProperty p(object.data(), "MyContainer.foo" , qmlContext(object.data())); |
1274 | QCOMPARE(p.read(), QVariant(10)); |
1275 | } |
1276 | { |
1277 | QQmlComponent component(&engine); |
1278 | component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }" , baseUrl: QUrl()); |
1279 | QScopedPointer<QObject> object(component.create()); |
1280 | QVERIFY(object != nullptr); |
1281 | |
1282 | QQmlProperty p(object.data(), "Foo.MyContainer.foo" , qmlContext(object.data())); |
1283 | QCOMPARE(p.read(), QVariant(10)); |
1284 | } |
1285 | { // static |
1286 | QQmlComponent component(&engine); |
1287 | component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }" , baseUrl: QUrl()); |
1288 | QScopedPointer<QObject> object(component.create()); |
1289 | QVERIFY(object != nullptr); |
1290 | |
1291 | QCOMPARE(QQmlProperty::read(object.data(), "Foo.MyContainer.foo" , |
1292 | qmlContext(object.data())), QVariant(10)); |
1293 | } |
1294 | } |
1295 | |
1296 | void tst_qqmlproperty::write() |
1297 | { |
1298 | // Invalid |
1299 | { |
1300 | QQmlProperty p; |
1301 | QCOMPARE(p.write(QVariant(10)), false); |
1302 | } |
1303 | |
1304 | // Read-only default prop |
1305 | { |
1306 | PropertyObject o; |
1307 | QQmlProperty p(&o); |
1308 | QCOMPARE(p.write(QVariant(10)), false); |
1309 | } |
1310 | |
1311 | // Invalid default prop |
1312 | { |
1313 | QObject o; |
1314 | QQmlProperty p(&o); |
1315 | QCOMPARE(p.write(QVariant(10)), false); |
1316 | } |
1317 | |
1318 | // Read-only prop by name |
1319 | { |
1320 | PropertyObject o; |
1321 | QQmlProperty p(&o, QString("defaultProperty" )); |
1322 | QCOMPARE(p.write(QVariant(10)), false); |
1323 | } |
1324 | |
1325 | // Writable prop by name |
1326 | { |
1327 | PropertyObject o; |
1328 | QQmlProperty p(&o, QString("objectName" )); |
1329 | QCOMPARE(o.objectName(), QString()); |
1330 | QCOMPARE(p.write(QVariant(QString("myName" ))), true); |
1331 | QCOMPARE(o.objectName(), QString("myName" )); |
1332 | } |
1333 | |
1334 | // Writable prop by name (static) |
1335 | { |
1336 | PropertyObject o; |
1337 | QCOMPARE(QQmlProperty::write(&o, QString("objectName" ), QVariant(QString("myName" ))), true); |
1338 | QCOMPARE(o.objectName(), QString("myName" )); |
1339 | } |
1340 | |
1341 | // Deleted object |
1342 | { |
1343 | PropertyObject *o = new PropertyObject; |
1344 | QQmlProperty p(o, QString("objectName" )); |
1345 | QCOMPARE(p.write(QVariant(QString("myName" ))), true); |
1346 | QCOMPARE(o->objectName(), QString("myName" )); |
1347 | |
1348 | delete o; |
1349 | |
1350 | QCOMPARE(p.write(QVariant(QString("myName" ))), false); |
1351 | } |
1352 | |
1353 | // Signal property |
1354 | { |
1355 | PropertyObject o; |
1356 | QQmlProperty p(&o, "onClicked" ); |
1357 | QCOMPARE(p.write(QVariant("console.log(1921)" )), false); |
1358 | |
1359 | QQmlPropertyPrivate::takeSignalExpression(that: p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1)); |
1360 | QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p)); |
1361 | |
1362 | QCOMPARE(p.write(QVariant("console.log(1921)" )), false); |
1363 | |
1364 | QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p)); |
1365 | } |
1366 | |
1367 | // Automatic signal property |
1368 | { |
1369 | PropertyObject o; |
1370 | QQmlProperty p(&o, "onPropertyWithNotifyChanged" ); |
1371 | QCOMPARE(p.write(QVariant("console.log(1921)" )), false); |
1372 | |
1373 | QQmlPropertyPrivate::takeSignalExpression(that: p, new QQmlBoundSignalExpression(&o, QQmlPropertyPrivate::get(p)->signalIndex(), QQmlContextData::get(context: engine.rootContext()), nullptr, QLatin1String("null" ), QString(), -1, -1)); |
1374 | QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p)); |
1375 | |
1376 | QCOMPARE(p.write(QVariant("console.log(1921)" )), false); |
1377 | |
1378 | QVERIFY(nullptr != QQmlPropertyPrivate::signalExpression(p)); |
1379 | } |
1380 | |
1381 | // Value-type property |
1382 | { |
1383 | PropertyObject o; |
1384 | QQmlProperty p(&o, "wrectProperty" ); |
1385 | |
1386 | QCOMPARE(o.wrectProperty(), QRect()); |
1387 | QCOMPARE(p.write(QRect(1, 13, 99, 8)), true); |
1388 | QCOMPARE(o.wrectProperty(), QRect(1, 13, 99, 8)); |
1389 | |
1390 | QQmlProperty p2(&o, "wrectProperty.x" ); |
1391 | QCOMPARE(p2.read(), QVariant(1)); |
1392 | QCOMPARE(p2.write(QVariant(6)), true); |
1393 | QCOMPARE(p2.read(), QVariant(6)); |
1394 | QCOMPARE(o.wrectProperty(), QRect(6, 13, 99, 8)); |
1395 | } |
1396 | |
1397 | // URL-property |
1398 | { |
1399 | PropertyObject o; |
1400 | QQmlProperty p(&o, "url" ); |
1401 | |
1402 | QCOMPARE(p.write(QUrl("main.qml" )), true); |
1403 | QCOMPARE(o.url(), QUrl("main.qml" )); |
1404 | |
1405 | QQmlProperty p2(&o, "url" , engine.rootContext()); |
1406 | |
1407 | QUrl result = engine.baseUrl().resolved(relative: QUrl("main.qml" )); |
1408 | QVERIFY(result != QUrl("main.qml" )); |
1409 | |
1410 | QCOMPARE(p2.write(QUrl("main.qml" )), true); |
1411 | QCOMPARE(o.url(), result); |
1412 | } |
1413 | { // static |
1414 | PropertyObject o; |
1415 | |
1416 | QCOMPARE(QQmlProperty::write(&o, "url" , QUrl("main.qml" )), true); |
1417 | QCOMPARE(o.url(), QUrl("main.qml" )); |
1418 | |
1419 | QUrl result = engine.baseUrl().resolved(relative: QUrl("main.qml" )); |
1420 | QVERIFY(result != QUrl("main.qml" )); |
1421 | |
1422 | QCOMPARE(QQmlProperty::write(&o, "url" , QUrl("main.qml" ), engine.rootContext()), true); |
1423 | QCOMPARE(o.url(), result); |
1424 | } |
1425 | |
1426 | // Char/string-property |
1427 | { |
1428 | PropertyObject o; |
1429 | QQmlProperty qcharProperty(&o, "qcharProperty" ); |
1430 | QQmlProperty stringProperty(&o, "stringProperty" ); |
1431 | |
1432 | const int black_circle = 0x25cf; |
1433 | |
1434 | QCOMPARE(qcharProperty.write(QString("foo" )), false); |
1435 | QCOMPARE(qcharProperty.write('Q'), true); |
1436 | QCOMPARE(qcharProperty.read(), QVariant('Q')); |
1437 | QCOMPARE(qcharProperty.write(QChar(black_circle)), true); |
1438 | QCOMPARE(qcharProperty.read(), QVariant(QChar(black_circle))); |
1439 | |
1440 | QCOMPARE(o.stringProperty(), QString("foo" )); // Default value |
1441 | QCOMPARE(stringProperty.write(QString("bar" )), true); |
1442 | QCOMPARE(o.stringProperty(), QString("bar" )); |
1443 | QCOMPARE(stringProperty.write(QVariant(1234)), true); |
1444 | QCOMPARE(stringProperty.read().toString(), QString::number(1234)); |
1445 | QCOMPARE(stringProperty.write('A'), true); |
1446 | QCOMPARE(stringProperty.read().toString(), QString::number('A')); |
1447 | QCOMPARE(stringProperty.write(QChar(black_circle)), true); |
1448 | QCOMPARE(stringProperty.read(), QVariant(QChar(black_circle))); |
1449 | |
1450 | { // QChar -> QString |
1451 | QQmlComponent component(&engine); |
1452 | component.setData("import Test 1.0\nPropertyObject { stringProperty: constQChar }" , baseUrl: QUrl()); |
1453 | QScopedPointer<QObject> object(component.create()); |
1454 | PropertyObject *propertyObject = qobject_cast<PropertyObject*>(object: object.data()); |
1455 | QVERIFY(propertyObject != nullptr); |
1456 | if (propertyObject) { |
1457 | QQmlProperty stringProperty(propertyObject, "stringProperty" ); |
1458 | QCOMPARE(stringProperty.read(), QVariant(QString(propertyObject->constQChar()))); |
1459 | } |
1460 | } |
1461 | |
1462 | } |
1463 | |
1464 | // VariantMap-property |
1465 | QVariantMap vm; |
1466 | vm.insert(key: "key" , value: "value" ); |
1467 | |
1468 | { |
1469 | PropertyObject o; |
1470 | QQmlProperty p(&o, "variantMap" ); |
1471 | |
1472 | QCOMPARE(p.write(vm), true); |
1473 | QCOMPARE(o.variantMap(), vm); |
1474 | |
1475 | QQmlProperty p2(&o, "variantMap" , engine.rootContext()); |
1476 | |
1477 | QCOMPARE(p2.write(vm), true); |
1478 | QCOMPARE(o.variantMap(), vm); |
1479 | } |
1480 | { // static |
1481 | PropertyObject o; |
1482 | |
1483 | QCOMPARE(QQmlProperty::write(&o, "variantMap" , vm), true); |
1484 | QCOMPARE(o.variantMap(), vm); |
1485 | |
1486 | QCOMPARE(QQmlProperty::write(&o, "variantMap" , vm, engine.rootContext()), true); |
1487 | QCOMPARE(o.variantMap(), vm); |
1488 | } |
1489 | |
1490 | // Attached property |
1491 | { |
1492 | QQmlComponent component(&engine); |
1493 | component.setData("import Test 1.0\nMyContainer { }" , baseUrl: QUrl()); |
1494 | QObject *object = component.create(); |
1495 | QVERIFY(object != nullptr); |
1496 | |
1497 | QQmlProperty p(object, "MyContainer.foo" , qmlContext(object)); |
1498 | p.write(QVariant(99)); |
1499 | QCOMPARE(p.read(), QVariant(99)); |
1500 | delete object; |
1501 | } |
1502 | { |
1503 | QQmlComponent component(&engine); |
1504 | component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }" , baseUrl: QUrl()); |
1505 | QObject *object = component.create(); |
1506 | QVERIFY(object != nullptr); |
1507 | |
1508 | QQmlProperty p(object, "Foo.MyContainer.foo" , qmlContext(object)); |
1509 | p.write(QVariant(99)); |
1510 | QCOMPARE(p.read(), QVariant(99)); |
1511 | delete object; |
1512 | } |
1513 | // Writable pointer to QObject derived |
1514 | { |
1515 | PropertyObject o; |
1516 | QQmlProperty p(&o, QString("qObject" )); |
1517 | QCOMPARE(o.qObject(), (QObject*)nullptr); |
1518 | QObject *newObject = new MyQObject(this); |
1519 | QCOMPARE(p.write(QVariant::fromValue(newObject)), true); |
1520 | QCOMPARE(o.qObject(), newObject); |
1521 | QVariant data = p.read(); |
1522 | QCOMPARE(data.value<QObject*>(), newObject); |
1523 | QCOMPARE(data.value<MyQObject*>(), newObject); |
1524 | // Incompatible types can not be written. |
1525 | QCOMPARE(p.write(QVariant::fromValue(new MyQmlObject(this))), false); |
1526 | QVariant newData = p.read(); |
1527 | QCOMPARE(newData.value<QObject*>(), newObject); |
1528 | QCOMPARE(newData.value<MyQObject*>(), newObject); |
1529 | } |
1530 | { |
1531 | QQmlEngine engine; |
1532 | PropertyObject o; |
1533 | QQmlProperty p(&o, QString("qObject" ), &engine); |
1534 | QCOMPARE(o.qObject(), (QObject*)nullptr); |
1535 | QObject *newObject = new MyQObject(this); |
1536 | QCOMPARE(p.write(QVariant::fromValue(newObject)), true); |
1537 | QCOMPARE(o.qObject(), newObject); |
1538 | QVariant data = p.read(); |
1539 | QCOMPARE(data.value<QObject*>(), newObject); |
1540 | QCOMPARE(data.value<MyQObject*>(), newObject); |
1541 | // Incompatible types can not be written. |
1542 | QCOMPARE(p.write(QVariant::fromValue(new MyQmlObject(this))), false); |
1543 | QVariant newData = p.read(); |
1544 | QCOMPARE(newData.value<QObject*>(), newObject); |
1545 | QCOMPARE(newData.value<MyQObject*>(), newObject); |
1546 | } |
1547 | } |
1548 | |
1549 | void tst_qqmlproperty::reset() |
1550 | { |
1551 | // Invalid |
1552 | { |
1553 | QQmlProperty p; |
1554 | QCOMPARE(p.isResettable(), false); |
1555 | QCOMPARE(p.reset(), false); |
1556 | } |
1557 | |
1558 | // Read-only default prop |
1559 | { |
1560 | PropertyObject o; |
1561 | QQmlProperty p(&o); |
1562 | QCOMPARE(p.isResettable(), false); |
1563 | QCOMPARE(p.reset(), false); |
1564 | } |
1565 | |
1566 | // Invalid default prop |
1567 | { |
1568 | QObject o; |
1569 | QQmlProperty p(&o); |
1570 | QCOMPARE(p.isResettable(), false); |
1571 | QCOMPARE(p.reset(), false); |
1572 | } |
1573 | |
1574 | // Non-resettable-only prop by name |
1575 | { |
1576 | PropertyObject o; |
1577 | QQmlProperty p(&o, QString("defaultProperty" )); |
1578 | QCOMPARE(p.isResettable(), false); |
1579 | QCOMPARE(p.reset(), false); |
1580 | } |
1581 | |
1582 | // Resettable prop by name |
1583 | { |
1584 | PropertyObject o; |
1585 | QQmlProperty p(&o, QString("resettableProperty" )); |
1586 | |
1587 | QCOMPARE(p.read(), QVariant(9)); |
1588 | QCOMPARE(p.write(QVariant(11)), true); |
1589 | QCOMPARE(p.read(), QVariant(11)); |
1590 | |
1591 | QCOMPARE(p.isResettable(), true); |
1592 | QCOMPARE(p.reset(), true); |
1593 | |
1594 | QCOMPARE(p.read(), QVariant(9)); |
1595 | } |
1596 | |
1597 | // Deleted object |
1598 | { |
1599 | PropertyObject *o = new PropertyObject; |
1600 | |
1601 | QQmlProperty p(o, QString("resettableProperty" )); |
1602 | |
1603 | QCOMPARE(p.isResettable(), true); |
1604 | QCOMPARE(p.reset(), true); |
1605 | |
1606 | delete o; |
1607 | |
1608 | QCOMPARE(p.isResettable(), false); |
1609 | QCOMPARE(p.reset(), false); |
1610 | } |
1611 | |
1612 | // Signal property |
1613 | { |
1614 | PropertyObject o; |
1615 | QQmlProperty p(&o, "onClicked" ); |
1616 | |
1617 | QCOMPARE(p.isResettable(), false); |
1618 | QCOMPARE(p.reset(), false); |
1619 | } |
1620 | |
1621 | // Automatic signal property |
1622 | { |
1623 | PropertyObject o; |
1624 | QQmlProperty p(&o, "onPropertyWithNotifyChanged" ); |
1625 | |
1626 | QCOMPARE(p.isResettable(), false); |
1627 | QCOMPARE(p.reset(), false); |
1628 | } |
1629 | } |
1630 | |
1631 | void tst_qqmlproperty::writeObjectToList() |
1632 | { |
1633 | QQmlComponent containerComponent(&engine); |
1634 | containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }" , baseUrl: QUrl()); |
1635 | QScopedPointer<QObject> object(containerComponent.create()); |
1636 | MyContainer *container = qobject_cast<MyContainer*>(object: object.data()); |
1637 | QVERIFY(container != nullptr); |
1638 | QQmlListReference list(container, "children" ); |
1639 | QCOMPARE(list.count(), 1); |
1640 | |
1641 | QScopedPointer<MyQmlObject> childObject(new MyQmlObject); |
1642 | QQmlProperty prop(container, "children" ); |
1643 | prop.write(QVariant::fromValue(value: childObject.data())); |
1644 | QCOMPARE(list.count(), 1); |
1645 | QCOMPARE(list.at(0), qobject_cast<QObject*>(childObject.data())); |
1646 | } |
1647 | |
1648 | void tst_qqmlproperty::writeListToList() |
1649 | { |
1650 | QQmlComponent containerComponent(&engine); |
1651 | containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }" , baseUrl: QUrl()); |
1652 | QScopedPointer<QObject> object(containerComponent.create()); |
1653 | MyContainer *container = qobject_cast<MyContainer*>(object: object.data()); |
1654 | QVERIFY(container != nullptr); |
1655 | QQmlListReference list(container, "children" ); |
1656 | QCOMPARE(list.count(), 1); |
1657 | |
1658 | QList<QObject*> objList; |
1659 | objList << new MyQmlObject(this) << new MyQmlObject(this) |
1660 | << new MyQmlObject(this) << new MyQmlObject(this); |
1661 | QQmlProperty prop(container, "children" ); |
1662 | prop.write(QVariant::fromValue(value: objList)); |
1663 | QCOMPARE(list.count(), 4); |
1664 | |
1665 | //XXX need to try this with read/write prop (for read-only it correctly doesn't write) |
1666 | /*QList<MyQmlObject*> typedObjList; |
1667 | typedObjList << new MyQmlObject(); |
1668 | prop.write(QVariant::fromValue(&typedObjList)); |
1669 | QCOMPARE(container->children()->size(), 1);*/ |
1670 | } |
1671 | |
1672 | void tst_qqmlproperty::urlHandling_data() |
1673 | { |
1674 | QTest::addColumn<QByteArray>(name: "input" ); |
1675 | QTest::addColumn<QString>(name: "scheme" ); |
1676 | QTest::addColumn<QString>(name: "path" ); |
1677 | QTest::addColumn<QByteArray>(name: "encoded" ); |
1678 | |
1679 | QTest::newRow(dataTag: "unspecifiedFile" ) |
1680 | << QByteArray("main.qml" ) |
1681 | << QString("" ) |
1682 | << QString("main.qml" ) |
1683 | << QByteArray("main.qml" ); |
1684 | |
1685 | QTest::newRow(dataTag: "specifiedFile" ) |
1686 | << QByteArray("file:///main.qml" ) |
1687 | << QString("file" ) |
1688 | << QString("/main.qml" ) |
1689 | << QByteArray("file:///main.qml" ); |
1690 | |
1691 | QTest::newRow(dataTag: "httpFile" ) |
1692 | << QByteArray("http://www.example.com/main.qml" ) |
1693 | << QString("http" ) |
1694 | << QString("/main.qml" ) |
1695 | << QByteArray("http://www.example.com/main.qml" ); |
1696 | |
1697 | QTest::newRow(dataTag: "pathFile" ) |
1698 | << QByteArray("http://www.example.com/resources/main.qml" ) |
1699 | << QString("http" ) |
1700 | << QString("/resources/main.qml" ) |
1701 | << QByteArray("http://www.example.com/resources/main.qml" ); |
1702 | |
1703 | QTest::newRow(dataTag: "encodableName" ) |
1704 | << QByteArray("http://www.example.com/main file.qml" ) |
1705 | << QString("http" ) |
1706 | << QString("/main file.qml" ) |
1707 | << QByteArray("http://www.example.com/main%20file.qml" ); |
1708 | |
1709 | QTest::newRow(dataTag: "preencodedName" ) |
1710 | << QByteArray("http://www.example.com/resources%7Cmain%20file.qml" ) |
1711 | << QString("http" ) |
1712 | << QString("/resources|main file.qml" ) |
1713 | << QByteArray("http://www.example.com/resources%7Cmain%20file.qml" ); |
1714 | |
1715 | QTest::newRow(dataTag: "encodableQuery" ) |
1716 | << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now working?" ) |
1717 | << QString("http" ) |
1718 | << QString("/main.qml" ) |
1719 | << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working?" ); |
1720 | |
1721 | // Although 'text%2Fqml' is pre-encoded, it will be decoded to allow correct QUrl classification |
1722 | QTest::newRow(dataTag: "preencodedQuery" ) |
1723 | << QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now working%3F" ) |
1724 | << QString("http" ) |
1725 | << QString("/main.qml" ) |
1726 | << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working%3F" ); |
1727 | |
1728 | QTest::newRow(dataTag: "encodableFragment" ) |
1729 | << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000|volume+50%" ) |
1730 | << QString("http" ) |
1731 | << QString("/main.qml" ) |
1732 | << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7Cvolume+50%25" ); |
1733 | |
1734 | QTest::newRow(dataTag: "improperlyEncodedFragment" ) |
1735 | << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7Cvolume%2B50%" ) |
1736 | << QString("http" ) |
1737 | << QString("/main.qml" ) |
1738 | << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%257Cvolume%252B50%25" ); |
1739 | } |
1740 | |
1741 | void tst_qqmlproperty::urlHandling() |
1742 | { |
1743 | QFETCH(QByteArray, input); |
1744 | QFETCH(QString, scheme); |
1745 | QFETCH(QString, path); |
1746 | QFETCH(QByteArray, encoded); |
1747 | |
1748 | QString inputString(QString::fromUtf8(str: input)); |
1749 | |
1750 | { |
1751 | PropertyObject o; |
1752 | QQmlProperty p(&o, "url" ); |
1753 | |
1754 | // Test url written as QByteArray |
1755 | QCOMPARE(p.write(input), true); |
1756 | QUrl byteArrayResult(o.url()); |
1757 | |
1758 | QCOMPARE(byteArrayResult.scheme(), scheme); |
1759 | QCOMPARE(byteArrayResult.path(), path); |
1760 | QCOMPARE(byteArrayResult.toString(QUrl::FullyEncoded), QString::fromUtf8(encoded)); |
1761 | QCOMPARE(byteArrayResult.toEncoded(), encoded); |
1762 | } |
1763 | |
1764 | { |
1765 | PropertyObject o; |
1766 | QQmlProperty p(&o, "url" ); |
1767 | |
1768 | // Test url written as QString |
1769 | QCOMPARE(p.write(inputString), true); |
1770 | QUrl stringResult(o.url()); |
1771 | |
1772 | QCOMPARE(stringResult.scheme(), scheme); |
1773 | QCOMPARE(stringResult.path(), path); |
1774 | QCOMPARE(stringResult.toString(QUrl::FullyEncoded), QString::fromUtf8(encoded)); |
1775 | QCOMPARE(stringResult.toEncoded(), encoded); |
1776 | } |
1777 | } |
1778 | |
1779 | void tst_qqmlproperty::variantMapHandling_data() |
1780 | { |
1781 | QTest::addColumn<QVariantMap>(name: "vm" ); |
1782 | |
1783 | // Object literals |
1784 | { |
1785 | QVariantMap m; |
1786 | QTest::newRow(dataTag: "{}" ) << m; |
1787 | } |
1788 | { |
1789 | QVariantMap m; |
1790 | m["a" ] = QVariantMap(); |
1791 | QTest::newRow(dataTag: "{ a:{} }" ) << m; |
1792 | } |
1793 | { |
1794 | QVariantMap m, m2; |
1795 | m2["b" ] = 10; |
1796 | m2["c" ] = 20; |
1797 | m["a" ] = m2; |
1798 | QTest::newRow(dataTag: "{ a:{b:10, c:20} }" ) << m; |
1799 | } |
1800 | { |
1801 | QVariantMap m; |
1802 | m["a" ] = 10; |
1803 | m["b" ] = QVariantList() << 20 << 30; |
1804 | QTest::newRow(dataTag: "{ a:10, b:[20, 30]}" ) << m; |
1805 | } |
1806 | |
1807 | // Cyclic objects |
1808 | { |
1809 | QVariantMap m; |
1810 | m["p" ] = QVariantMap(); |
1811 | QTest::newRow(dataTag: "var o={}; o.p=o" ) << m; |
1812 | } |
1813 | { |
1814 | QVariantMap m; |
1815 | m["p" ] = 123; |
1816 | m["q" ] = QVariantMap(); |
1817 | QTest::newRow(dataTag: "var o={}; o.p=123; o.q=o" ) << m; |
1818 | } |
1819 | } |
1820 | |
1821 | void tst_qqmlproperty::variantMapHandling() |
1822 | { |
1823 | QFETCH(QVariantMap, vm); |
1824 | |
1825 | PropertyObject o; |
1826 | QQmlProperty p(&o, "variantMap" ); |
1827 | |
1828 | QCOMPARE(p.write(vm), true); |
1829 | QCOMPARE(o.variantMap(), vm); |
1830 | } |
1831 | |
1832 | void tst_qqmlproperty::crashOnValueProperty() |
1833 | { |
1834 | QQmlEngine *engine = new QQmlEngine; |
1835 | QQmlComponent component(engine); |
1836 | |
1837 | component.setData("import Test 1.0\nPropertyObject { wrectProperty.x: 10 }" , baseUrl: QUrl()); |
1838 | QScopedPointer<QObject> object(component.create()); |
1839 | PropertyObject *propertyObject = qobject_cast<PropertyObject*>(object: object.data()); |
1840 | QVERIFY(propertyObject != nullptr); |
1841 | |
1842 | QQmlProperty p(propertyObject, "wrectProperty.x" , qmlContext(propertyObject)); |
1843 | QCOMPARE(p.name(), QString("wrectProperty.x" )); |
1844 | |
1845 | QCOMPARE(p.read(), QVariant(10)); |
1846 | |
1847 | //don't crash once the engine is deleted |
1848 | delete engine; |
1849 | engine = nullptr; |
1850 | |
1851 | QCOMPARE(p.propertyTypeName(), "int" ); |
1852 | QCOMPARE(p.read(), QVariant(10)); |
1853 | p.write(QVariant(20)); |
1854 | QCOMPARE(p.read(), QVariant(20)); |
1855 | } |
1856 | |
1857 | void tst_qqmlproperty::aliasPropertyBindings_data() |
1858 | { |
1859 | QTest::addColumn<QString>(name: "file" ); |
1860 | QTest::addColumn<QString>(name: "subObject" ); |
1861 | |
1862 | QTest::newRow(dataTag: "same object" ) << "aliasPropertyBindings.qml" << "" ; |
1863 | QTest::newRow(dataTag: "different objects" ) << "aliasPropertyBindings2.qml" << "innerObject" ; |
1864 | } |
1865 | |
1866 | // QTBUG-13719, QTBUG-58271 |
1867 | void tst_qqmlproperty::aliasPropertyBindings() |
1868 | { |
1869 | QFETCH(QString, file); |
1870 | QFETCH(QString, subObject); |
1871 | |
1872 | QQmlComponent component(&engine, testFileUrl(fileName: file)); |
1873 | |
1874 | QObject *object = component.create(); |
1875 | QVERIFY(object != nullptr); |
1876 | |
1877 | // the object where realProperty lives |
1878 | QObject *realPropertyObject = object; |
1879 | if (!subObject.isEmpty()) |
1880 | realPropertyObject = object->property(name: subObject.toLatin1()).value<QObject*>(); |
1881 | |
1882 | QCOMPARE(realPropertyObject->property("realProperty" ).toReal(), 90.); |
1883 | QCOMPARE(object->property("aliasProperty" ).toReal(), 90.); |
1884 | |
1885 | object->setProperty(name: "test" , value: 10); |
1886 | |
1887 | QCOMPARE(realPropertyObject->property("realProperty" ).toReal(), 110.); |
1888 | QCOMPARE(object->property("aliasProperty" ).toReal(), 110.); |
1889 | |
1890 | QQmlProperty realProperty(realPropertyObject, QLatin1String("realProperty" )); |
1891 | QQmlProperty aliasProperty(object, QLatin1String("aliasProperty" )); |
1892 | |
1893 | // Check there is a binding on these two properties |
1894 | QVERIFY(QQmlPropertyPrivate::binding(realProperty) != nullptr); |
1895 | QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != nullptr); |
1896 | |
1897 | // Check that its the same binding on these two properties |
1898 | QCOMPARE(QQmlPropertyPrivate::binding(realProperty), |
1899 | QQmlPropertyPrivate::binding(aliasProperty)); |
1900 | |
1901 | // Change the binding |
1902 | object->setProperty(name: "state" , value: QString("switch" )); |
1903 | |
1904 | QVERIFY(QQmlPropertyPrivate::binding(realProperty) != nullptr); |
1905 | QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != nullptr); |
1906 | QCOMPARE(QQmlPropertyPrivate::binding(realProperty), |
1907 | QQmlPropertyPrivate::binding(aliasProperty)); |
1908 | |
1909 | QCOMPARE(realPropertyObject->property("realProperty" ).toReal(), 96.); |
1910 | QCOMPARE(object->property("aliasProperty" ).toReal(), 96.); |
1911 | |
1912 | // Check the old binding really has not effect any more |
1913 | object->setProperty(name: "test" , value: 4); |
1914 | |
1915 | QCOMPARE(realPropertyObject->property("realProperty" ).toReal(), 96.); |
1916 | QCOMPARE(object->property("aliasProperty" ).toReal(), 96.); |
1917 | |
1918 | object->setProperty(name: "test2" , value: 9); |
1919 | |
1920 | QCOMPARE(realPropertyObject->property("realProperty" ).toReal(), 288.); |
1921 | QCOMPARE(object->property("aliasProperty" ).toReal(), 288.); |
1922 | |
1923 | // Revert |
1924 | object->setProperty(name: "state" , value: QString("" )); |
1925 | |
1926 | QVERIFY(QQmlPropertyPrivate::binding(realProperty) != nullptr); |
1927 | QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != nullptr); |
1928 | QCOMPARE(QQmlPropertyPrivate::binding(realProperty), |
1929 | QQmlPropertyPrivate::binding(aliasProperty)); |
1930 | |
1931 | QCOMPARE(realPropertyObject->property("realProperty" ).toReal(), 20.); |
1932 | QCOMPARE(object->property("aliasProperty" ).toReal(), 20.); |
1933 | |
1934 | object->setProperty(name: "test2" , value: 3); |
1935 | |
1936 | QCOMPARE(realPropertyObject->property("realProperty" ).toReal(), 20.); |
1937 | QCOMPARE(object->property("aliasProperty" ).toReal(), 20.); |
1938 | |
1939 | delete object; |
1940 | } |
1941 | |
1942 | void tst_qqmlproperty::copy() |
1943 | { |
1944 | PropertyObject object; |
1945 | |
1946 | QScopedPointer<QQmlProperty> property( |
1947 | new QQmlProperty(&object, QLatin1String("defaultProperty" ))); |
1948 | QCOMPARE(property->name(), QString("defaultProperty" )); |
1949 | QCOMPARE(property->read(), QVariant(10)); |
1950 | QCOMPARE(property->type(), QQmlProperty::Property); |
1951 | QCOMPARE(property->propertyTypeCategory(), QQmlProperty::Normal); |
1952 | QCOMPARE(property->propertyType(), (int)QVariant::Int); |
1953 | |
1954 | QQmlProperty p1(*property); |
1955 | QCOMPARE(p1.name(), QString("defaultProperty" )); |
1956 | QCOMPARE(p1.read(), QVariant(10)); |
1957 | QCOMPARE(p1.type(), QQmlProperty::Property); |
1958 | QCOMPARE(p1.propertyTypeCategory(), QQmlProperty::Normal); |
1959 | QCOMPARE(p1.propertyType(), (int)QVariant::Int); |
1960 | |
1961 | QQmlProperty p2(&object, QLatin1String("url" )); |
1962 | QCOMPARE(p2.name(), QString("url" )); |
1963 | p2 = *property; |
1964 | QCOMPARE(p2.name(), QString("defaultProperty" )); |
1965 | QCOMPARE(p2.read(), QVariant(10)); |
1966 | QCOMPARE(p2.type(), QQmlProperty::Property); |
1967 | QCOMPARE(p2.propertyTypeCategory(), QQmlProperty::Normal); |
1968 | QCOMPARE(p2.propertyType(), (int)QVariant::Int); |
1969 | |
1970 | property.reset(); |
1971 | |
1972 | QCOMPARE(p1.name(), QString("defaultProperty" )); |
1973 | QCOMPARE(p1.read(), QVariant(10)); |
1974 | QCOMPARE(p1.type(), QQmlProperty::Property); |
1975 | QCOMPARE(p1.propertyTypeCategory(), QQmlProperty::Normal); |
1976 | QCOMPARE(p1.propertyType(), (int)QVariant::Int); |
1977 | |
1978 | QCOMPARE(p2.name(), QString("defaultProperty" )); |
1979 | QCOMPARE(p2.read(), QVariant(10)); |
1980 | QCOMPARE(p2.type(), QQmlProperty::Property); |
1981 | QCOMPARE(p2.propertyTypeCategory(), QQmlProperty::Normal); |
1982 | QCOMPARE(p2.propertyType(), (int)QVariant::Int); |
1983 | |
1984 | p1 = QQmlProperty(); |
1985 | QQmlPropertyPrivate *p2d = QQmlPropertyPrivate::get(p: p2); |
1986 | QCOMPARE(p2d->count(), 1); |
1987 | |
1988 | // Use a pointer to avoid compiler warning about self-assignment. |
1989 | QQmlProperty *p2p = &p2; |
1990 | *p2p = p2; |
1991 | |
1992 | QCOMPARE(p2d->count(), 1); |
1993 | } |
1994 | |
1995 | void tst_qqmlproperty::noContext() |
1996 | { |
1997 | QQmlComponent compA(&engine, testFileUrl(fileName: "NoContextTypeA.qml" )); |
1998 | QQmlComponent compB(&engine, testFileUrl(fileName: "NoContextTypeB.qml" )); |
1999 | |
2000 | QObject *a = compA.create(); |
2001 | QVERIFY(a != nullptr); |
2002 | QObject *b = compB.create(); |
2003 | QVERIFY(b != nullptr); |
2004 | |
2005 | QVERIFY(QQmlProperty::write(b, "myTypeA" , QVariant::fromValue(a), &engine)); |
2006 | |
2007 | delete a; |
2008 | delete b; |
2009 | } |
2010 | |
2011 | void tst_qqmlproperty::assignEmptyVariantMap() |
2012 | { |
2013 | PropertyObject o; |
2014 | |
2015 | QVariantMap map; |
2016 | map.insert(key: "key" , value: "value" ); |
2017 | o.setVariantMap(map); |
2018 | QCOMPARE(o.variantMap().count(), 1); |
2019 | QCOMPARE(o.variantMap().isEmpty(), false); |
2020 | |
2021 | |
2022 | QQmlComponent component(&engine, testFileUrl(fileName: "assignEmptyVariantMap.qml" )); |
2023 | QObject *obj = component.createWithInitialProperties(initialProperties: {{"o" , QVariant::fromValue(value: &o)}}); |
2024 | QVERIFY(obj); |
2025 | |
2026 | QCOMPARE(o.variantMap().count(), 0); |
2027 | QCOMPARE(o.variantMap().isEmpty(), true); |
2028 | |
2029 | delete obj; |
2030 | } |
2031 | |
2032 | void tst_qqmlproperty::warnOnInvalidBinding() |
2033 | { |
2034 | QUrl testUrl(testFileUrl(fileName: "invalidBinding.qml" )); |
2035 | QString expectedWarning; |
2036 | |
2037 | // V4 error message for property-to-property binding |
2038 | expectedWarning = testUrl.toString() + QString::fromLatin1(str: ":6:5: Unable to assign QQuickText to QQuickRectangle" ); |
2039 | QTest::ignoreMessage(type: QtWarningMsg, message: expectedWarning.toLatin1().constData()); |
2040 | |
2041 | // V8 error message for function-to-property binding |
2042 | expectedWarning = testUrl.toString() + QString::fromLatin1(str: ":7:5: Unable to assign QQuickText to QQuickRectangle" ); |
2043 | QTest::ignoreMessage(type: QtWarningMsg, message: expectedWarning.toLatin1().constData()); |
2044 | |
2045 | #if QT_CONFIG(regularexpression) |
2046 | // V8 error message for invalid binding to anchor |
2047 | const QRegularExpression warning( |
2048 | "^" + testUrl.toString() |
2049 | + ":14:9: Unable to assign QQuickItem_QML_\\d+ to QQuickAnchorLine$" ); |
2050 | QTest::ignoreMessage(type: QtWarningMsg, messagePattern: warning); |
2051 | #endif |
2052 | |
2053 | QQmlComponent component(&engine, testUrl); |
2054 | QObject *obj = component.create(); |
2055 | QVERIFY(obj); |
2056 | delete obj; |
2057 | } |
2058 | |
2059 | void tst_qqmlproperty::deeplyNestedObject() |
2060 | { |
2061 | PropertyObject o; |
2062 | QQmlProperty p(&o, "qmlObject.pointProperty.x" ); |
2063 | QCOMPARE(p.isValid(), true); |
2064 | |
2065 | p.write(14); |
2066 | QCOMPARE(p.read(), QVariant(14)); |
2067 | } |
2068 | |
2069 | void tst_qqmlproperty::readOnlyDynamicProperties() |
2070 | { |
2071 | QQmlComponent comp(&engine, testFileUrl(fileName: "readonlyPrimitiveVsVar.qml" )); |
2072 | QObject *obj = comp.create(); |
2073 | QVERIFY(obj != nullptr); |
2074 | |
2075 | QVERIFY(!obj->metaObject()->property(obj->metaObject()->indexOfProperty("r_var" )).isWritable()); |
2076 | QVERIFY(!obj->metaObject()->property(obj->metaObject()->indexOfProperty("r_int" )).isWritable()); |
2077 | QVERIFY(obj->metaObject()->property(obj->metaObject()->indexOfProperty("w_var" )).isWritable()); |
2078 | QVERIFY(obj->metaObject()->property(obj->metaObject()->indexOfProperty("w_int" )).isWritable()); |
2079 | |
2080 | delete obj; |
2081 | } |
2082 | |
2083 | void tst_qqmlproperty::aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSystem() |
2084 | { |
2085 | const QUrl url = testFileUrl(fileName: "aliasToIdWithMatchingQmlFileName.qml" ); |
2086 | QQmlEngine engine; |
2087 | QQmlComponent component(&engine, url); |
2088 | QScopedPointer<QObject> root(component.create()); |
2089 | |
2090 | QQmlProperty property(root.data(), "testType.objectName" , QQmlEngine::contextForObject(root.data())); |
2091 | QVERIFY(property.isValid()); |
2092 | } |
2093 | |
2094 | // QTBUG-77027 |
2095 | void tst_qqmlproperty::nullPropertyBinding() |
2096 | { |
2097 | const QUrl url = testFileUrl(fileName: "nullPropertyBinding.qml" ); |
2098 | QQmlEngine engine; |
2099 | QQmlComponent component(&engine, url); |
2100 | QScopedPointer<QObject> root(component.create()); |
2101 | QVERIFY(root); |
2102 | QTest::ignoreMessage(type: QtMsgType::QtInfoMsg, message: "undefined" ); |
2103 | QMetaObject::invokeMethod(obj: root.get(), member: "tog" ); |
2104 | QTest::ignoreMessage(type: QtMsgType::QtInfoMsg, message: "defined" ); |
2105 | QMetaObject::invokeMethod(obj: root.get(), member: "tog" ); |
2106 | QTest::ignoreMessage(type: QtMsgType::QtInfoMsg, message: "undefined" ); |
2107 | QMetaObject::invokeMethod(obj: root.get(), member: "tog" ); |
2108 | } |
2109 | |
2110 | void tst_qqmlproperty::interfaceBinding() |
2111 | { |
2112 | qmlRegisterInterface<Interface>(typeName: "Interface" ); |
2113 | qmlRegisterType<A>(uri: "io.qt.bugreports" , versionMajor: 1, versionMinor: 0, qmlName: "A" ); |
2114 | qmlRegisterType<B>(uri: "io.qt.bugreports" , versionMajor: 1, versionMinor: 0, qmlName: "B" ); |
2115 | qmlRegisterType<C>(uri: "io.qt.bugreports" , versionMajor: 1, versionMinor: 0, qmlName: "C" ); |
2116 | qmlRegisterType<InterfaceConsumer>(uri: "io.qt.bugreports" , versionMajor: 1, versionMinor: 0, qmlName: "InterfaceConsumer" ); |
2117 | |
2118 | const QVector<QUrl> urls = { |
2119 | testFileUrl(fileName: "interfaceBinding.qml" ), |
2120 | testFileUrl(fileName: "interfaceBinding2.qml" ) |
2121 | }; |
2122 | |
2123 | for (const QUrl &url : urls) { |
2124 | QQmlEngine engine; |
2125 | QQmlComponent component(&engine, url); |
2126 | QScopedPointer<QObject> root(component.create()); |
2127 | QVERIFY(root); |
2128 | QCOMPARE(root->findChild<QObject*>("a1" )->property("testValue" ).toInt(), 42); |
2129 | QCOMPARE(root->findChild<QObject*>("a2" )->property("testValue" ).toInt(), 43); |
2130 | QCOMPARE(root->findChild<QObject*>("a3" )->property("testValue" ).toInt(), 44); |
2131 | } |
2132 | } |
2133 | |
2134 | void tst_qqmlproperty::floatToStringPrecision_data() |
2135 | { |
2136 | QTest::addColumn<QString>(name: "propertyName" ); |
2137 | QTest::addColumn<double>(name: "number" ); |
2138 | QTest::addColumn<QString>(name: "qtString" ); |
2139 | QTest::addColumn<QString>(name: "jsString" ); |
2140 | |
2141 | QTest::newRow(dataTag: "3.4" ) << "a" << 3.4 << "3.4" << "3.4" ; |
2142 | QTest::newRow(dataTag: "0.035003945" ) << "b" << 0.035003945 << "0.035003945" << "0.035003945" ; |
2143 | QTest::newRow(dataTag: "0.0000012345" ) << "c" << 0.0000012345 << "1.2345e-06" << "0.0000012345" ; |
2144 | QTest::newRow(dataTag: "0.00000012345" ) << "d" << 0.00000012345 << "1.2345e-07" << "1.2345e-7" ; |
2145 | QTest::newRow(dataTag: "1e20" ) << "e" << 1e20 << "1e+20" << "100000000000000000000" ; |
2146 | QTest::newRow(dataTag: "1e21" ) << "f" << 1e21 << "1e+21" << "1e+21" ; |
2147 | } |
2148 | |
2149 | void tst_qqmlproperty::floatToStringPrecision() |
2150 | { |
2151 | QQmlComponent comp(&engine, testFileUrl(fileName: "floatToStringPrecision.qml" )); |
2152 | QScopedPointer<QObject> obj(comp.create()); |
2153 | QVERIFY(obj != nullptr); |
2154 | |
2155 | QFETCH(QString, propertyName); |
2156 | QFETCH(double, number); |
2157 | QFETCH(QString, qtString); |
2158 | QFETCH(QString, jsString); |
2159 | |
2160 | QByteArray name = propertyName.toLatin1(); |
2161 | QCOMPARE(obj->property(name).toDouble(), number); |
2162 | QCOMPARE(obj->property(name).toString(), qtString); |
2163 | |
2164 | QByteArray name1 = (propertyName + QLatin1Char('1')).toLatin1(); |
2165 | QCOMPARE(obj->property(name1).toDouble(), number); |
2166 | QCOMPARE(obj->property(name1).toString(), qtString); |
2167 | |
2168 | QByteArray name2 = (propertyName + QLatin1Char('2')).toLatin1(); |
2169 | QCOMPARE(obj->property(name2).toDouble(), number); |
2170 | QCOMPARE(obj->property(name2).toString(), jsString); |
2171 | } |
2172 | |
2173 | void tst_qqmlproperty::initTestCase() |
2174 | { |
2175 | QQmlDataTest::initTestCase(); |
2176 | qmlRegisterType<MyQmlObject>(uri: "Test" ,versionMajor: 1,versionMinor: 0,qmlName: "MyQmlObject" ); |
2177 | qmlRegisterType<PropertyObject>(uri: "Test" ,versionMajor: 1,versionMinor: 0,qmlName: "PropertyObject" ); |
2178 | qmlRegisterType<MyContainer>(uri: "Test" ,versionMajor: 1,versionMinor: 0,qmlName: "MyContainer" ); |
2179 | } |
2180 | |
2181 | // QTBUG-60908 |
2182 | void tst_qqmlproperty::bindingToAlias() |
2183 | { |
2184 | QQmlEngine engine; |
2185 | QQmlComponent component(&engine, testFileUrl(fileName: "aliasToBinding.qml" )); |
2186 | QScopedPointer<QObject> o(component.create()); |
2187 | QVERIFY(!o.isNull()); |
2188 | } |
2189 | |
2190 | void tst_qqmlproperty::nestedQQmlPropertyMap() |
2191 | { |
2192 | QQmlPropertyMap mainPropertyMap; |
2193 | QQmlPropertyMap nestedPropertyMap; |
2194 | QQmlPropertyMap deeplyNestedPropertyMap; |
2195 | |
2196 | mainPropertyMap.insert(key: "nesting1" , value: QVariant::fromValue(value: &nestedPropertyMap)); |
2197 | nestedPropertyMap.insert(key: "value" , value: 42); |
2198 | nestedPropertyMap.insert(key: "nesting2" , value: QVariant::fromValue(value: &deeplyNestedPropertyMap)); |
2199 | deeplyNestedPropertyMap.insert(key: "value" , value: "success" ); |
2200 | |
2201 | QQmlProperty value{&mainPropertyMap, "nesting1.value" }; |
2202 | QCOMPARE(value.read().toInt(), 42); |
2203 | |
2204 | QQmlProperty success{&mainPropertyMap, "nesting1.nesting2.value" }; |
2205 | QCOMPARE(success.read().toString(), QLatin1String("success" )); |
2206 | } |
2207 | |
2208 | void tst_qqmlproperty::underscorePropertyChangeHandler() |
2209 | { |
2210 | QQmlEngine engine; |
2211 | QQmlComponent component(&engine); |
2212 | component.setData(R"( |
2213 | import QtQuick 2.12 |
2214 | |
2215 | Item { |
2216 | property int __withUnderScore |
2217 | } |
2218 | )" , baseUrl: QUrl::fromLocalFile(localfile: "." )); |
2219 | QScopedPointer<QObject> root { component.create() }; |
2220 | QVERIFY(root); |
2221 | QQmlProperty changeHandler(root.get(), "on__WithUnderScoreChanged" ); |
2222 | QVERIFY(changeHandler.isValid()); |
2223 | QVERIFY(changeHandler.isSignalProperty()); |
2224 | } |
2225 | |
2226 | void tst_qqmlproperty::signalExpressionWithoutObject() |
2227 | { |
2228 | QQmlProperty invalid; |
2229 | QQmlPropertyPrivate::setSignalExpression(that: invalid, nullptr); |
2230 | QQmlBoundSignalExpression *expr = QQmlPropertyPrivate::signalExpression(that: invalid); |
2231 | QVERIFY(!expr); |
2232 | } |
2233 | |
2234 | QTEST_MAIN(tst_qqmlproperty) |
2235 | |
2236 | #include "tst_qqmlproperty.moc" |
2237 | |