Improve composite property type unit test
[profile/ivi/qtdeclarative.git] / tests / auto / qml / qqmlproperty / tst_qqmlproperty.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QtQml/qqmlengine.h>
43 #include <QtQml/qqmlcomponent.h>
44 #include <QtQml/qqmlcontext.h>
45 #include <QtQml/qqmlproperty.h>
46 #include <QtQml/private/qqmlproperty_p.h>
47 #include <private/qqmlbinding_p.h>
48 #include <private/qqmlboundsignal_p.h>
49 #include <QtWidgets/QLineEdit>
50 #include <QtCore/qfileinfo.h>
51 #include <QtCore/qdir.h>
52 #include "../../shared/util.h"
53
54 #include <QDebug>
55 class MyQmlObject : public QObject
56 {
57     Q_OBJECT
58 public:
59     MyQmlObject() {}
60 };
61
62 QML_DECLARE_TYPE(MyQmlObject);
63
64 class MyAttached : public QObject
65 {
66     Q_OBJECT
67     Q_PROPERTY(int foo READ foo WRITE setFoo)
68 public:
69     MyAttached(QObject *parent) : QObject(parent), m_foo(13) {}
70
71     int foo() const { return m_foo; }
72     void setFoo(int f) { m_foo = f; }
73
74 private:
75     int m_foo;
76 };
77
78 class MyContainer : public QObject
79 {
80     Q_OBJECT
81     Q_PROPERTY(QQmlListProperty<MyQmlObject> children READ children)
82 public:
83     MyContainer() {}
84
85     QQmlListProperty<MyQmlObject> children() { return QQmlListProperty<MyQmlObject>(this, m_children); }
86
87     static MyAttached *qmlAttachedProperties(QObject *o) {
88         return new MyAttached(o);
89     }
90
91 private:
92     QList<MyQmlObject*> m_children;
93 };
94
95 QML_DECLARE_TYPE(MyContainer);
96 QML_DECLARE_TYPEINFO(MyContainer, QML_HAS_ATTACHED_PROPERTIES)
97
98 class tst_qqmlproperty : public QQmlDataTest
99 {
100     Q_OBJECT
101 public:
102     tst_qqmlproperty() {}
103
104 private slots:
105     void initTestCase();
106
107     // Constructors
108     void qmlmetaproperty();
109     void qmlmetaproperty_object();
110     void qmlmetaproperty_object_string();
111     void qmlmetaproperty_object_context();
112     void qmlmetaproperty_object_string_context();
113
114     // Methods
115     void name();
116     void read();
117     void write();
118     void reset();
119
120     // Functionality
121     void writeObjectToList();
122     void writeListToList();
123
124     //writeToReadOnly();
125
126     void urlHandling_data();
127     void urlHandling();
128
129     void variantMapHandling_data();
130     void variantMapHandling();
131
132     // Bugs
133     void crashOnValueProperty();
134     void aliasPropertyBindings();
135     void noContext();
136     void assignEmptyVariantMap();
137     void warnOnInvalidBinding();
138     void registeredCompositeTypeProperty();
139
140     void copy();
141 private:
142     QQmlEngine engine;
143 };
144
145 void tst_qqmlproperty::qmlmetaproperty()
146 {
147     QQmlProperty prop;
148
149     QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
150     QVERIFY(binding != 0);
151     QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
152     QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
153     QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
154
155     QObject *obj = new QObject;
156
157     QCOMPARE(prop.name(), QString());
158     QCOMPARE(prop.read(), QVariant());
159     QCOMPARE(prop.write(QVariant()), false);
160     QCOMPARE(prop.hasNotifySignal(), false);
161     QCOMPARE(prop.needsNotifySignal(), false);
162     QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
163     QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
164     QCOMPARE(prop.connectNotifySignal(obj, 0), false);
165     QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
166     QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
167     QCOMPARE(prop.connectNotifySignal(obj, -1), false);
168     QVERIFY(!prop.method().isValid());
169     QCOMPARE(prop.type(), QQmlProperty::Invalid);
170     QCOMPARE(prop.isProperty(), false);
171     QCOMPARE(prop.isWritable(), false);
172     QCOMPARE(prop.isDesignable(), false);
173     QCOMPARE(prop.isResettable(), false);
174     QCOMPARE(prop.isSignalProperty(), false);
175     QCOMPARE(prop.isValid(), false);
176     QCOMPARE(prop.object(), (QObject *)0);
177     QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
178     QCOMPARE(prop.propertyType(), 0);
179     QCOMPARE(prop.propertyTypeName(), (const char *)0);
180     QVERIFY(prop.property().name() == 0);
181     QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
182     QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
183     QVERIFY(binding == 0);
184     QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
185     QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
186     QVERIFY(sigExprWatcher.wasDeleted());
187     QCOMPARE(prop.index(), -1);
188     QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
189
190     delete obj;
191 }
192
193 // 1 = equal, 0 = unknown, -1 = not equal.
194 static int compareVariantAndListReference(const QVariant &v, QQmlListReference &r)
195 {
196     if (QLatin1String(v.typeName()) != QLatin1String("QQmlListReference"))
197         return -1;
198
199     QQmlListReference lhs = v.value<QQmlListReference>();
200     if (lhs.isValid() != r.isValid())
201         return -1;
202
203     if (lhs.canCount() != r.canCount())
204         return -1;
205
206     if (!lhs.canCount()) {
207         if (lhs.canAt() != r.canAt())
208             return -1; // not equal.
209         return 0; // not sure if they're equal or not, and no way to tell.
210     }
211
212     // if we get here, we must be able to count.
213     if (lhs.count() != r.count())
214         return -1;
215
216     if (lhs.canAt() != r.canAt())
217         return -1;
218
219     if (!lhs.canAt())
220         return 0; // can count, but can't check element equality.
221
222     for (int i = 0; i < lhs.count(); ++i) {
223         if (lhs.at(i) != r.at(i)) {
224             return -1; // different elements :. not equal.
225         }
226     }
227
228     return 1; // equal.
229 }
230
231 void tst_qqmlproperty::registeredCompositeTypeProperty()
232 {
233     // Composite type properties
234     {
235         QQmlEngine engine;
236         QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeProperty.qml"));
237         QObject *obj = component.create();
238         QVERIFY(obj);
239
240         // create property accessors and check types.
241         QQmlProperty p1(obj, "first");
242         QQmlProperty p2(obj, "second");
243         QQmlProperty p3(obj, "third");
244         QQmlProperty p1e(obj, "first", &engine);
245         QQmlProperty p2e(obj, "second", &engine);
246         QQmlProperty p3e(obj, "third", &engine);
247         QVERIFY(p1.propertyType() == p2.propertyType());
248         QVERIFY(p1.propertyType() != p3.propertyType());
249
250         // check that the values are retrievable from CPP
251         QVariant first = obj->property("first");
252         QVariant second = obj->property("second");
253         QVariant third = obj->property("third");
254         QVERIFY(first.isValid());
255         QVERIFY(second.isValid());
256         QVERIFY(third.isValid());
257         // ensure that conversion from qobject-derived-ptr to qobject-ptr works.
258         QVERIFY(first.value<QObject*>());
259         QVERIFY(second.value<QObject*>());
260         QVERIFY(third.value<QObject*>());
261
262         // check that the values retrieved via QQmlProperty match those retrieved via QMetaProperty::read().
263         QCOMPARE(p1.read().value<QObject*>(), first.value<QObject*>());
264         QCOMPARE(p2.read().value<QObject*>(), second.value<QObject*>());
265         QCOMPARE(p3.read().value<QObject*>(), third.value<QObject*>());
266         QCOMPARE(p1e.read().value<QObject*>(), first.value<QObject*>());
267         QCOMPARE(p2e.read().value<QObject*>(), second.value<QObject*>());
268         QCOMPARE(p3e.read().value<QObject*>(), third.value<QObject*>());
269
270         delete obj;
271     }
272
273     // List-of-composite-type type properties
274     {
275         QQmlEngine engine;
276         QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeProperty.qml"));
277         QObject *obj = component.create();
278         QVERIFY(obj);
279
280         // create list property accessors and check types
281         QQmlProperty lp1e(obj, "fclist", &engine);
282         QQmlProperty lp2e(obj, "sclistOne", &engine);
283         QQmlProperty lp3e(obj, "sclistTwo", &engine);
284         QVERIFY(lp1e.propertyType() != lp2e.propertyType());
285         QVERIFY(lp2e.propertyType() == lp3e.propertyType());
286
287         // check that the list values are retrievable from CPP
288         QVariant firstList = obj->property("fclist");
289         QVariant secondList = obj->property("sclistOne");
290         QVariant thirdList = obj->property("sclistTwo");
291         QVERIFY(firstList.isValid());
292         QVERIFY(secondList.isValid());
293         QVERIFY(thirdList.isValid());
294
295         // check that the value returned by QQmlProperty::read() is equivalent to the list reference.
296         QQmlListReference r1(obj, "fclist", &engine);
297         QQmlListReference r2(obj, "sclistOne", &engine);
298         QQmlListReference r3(obj, "sclistTwo", &engine);
299         QCOMPARE(compareVariantAndListReference(lp1e.read(), r1), 1);
300         QCOMPARE(compareVariantAndListReference(lp2e.read(), r2), 1);
301         QCOMPARE(compareVariantAndListReference(lp3e.read(), r3), 1);
302
303         delete obj;
304     }
305 }
306
307 class PropertyObject : public QObject
308 {
309     Q_OBJECT
310     Q_PROPERTY(int defaultProperty READ defaultProperty)
311     Q_PROPERTY(QRect rectProperty READ rectProperty)
312     Q_PROPERTY(QRect wrectProperty READ wrectProperty WRITE setWRectProperty)
313     Q_PROPERTY(QUrl url READ url WRITE setUrl)
314     Q_PROPERTY(QVariantMap variantMap READ variantMap WRITE setVariantMap)
315     Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty)
316     Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal)
317     Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject)
318
319     Q_CLASSINFO("DefaultProperty", "defaultProperty")
320 public:
321     PropertyObject() : m_resetProperty(9) {}
322
323     int defaultProperty() { return 10; }
324     QRect rectProperty() { return QRect(10, 10, 1, 209); }
325
326     QRect wrectProperty() { return m_rect; }
327     void setWRectProperty(const QRect &r) { m_rect = r; }
328
329     QUrl url() { return m_url; }
330     void setUrl(const QUrl &u) { m_url = u; }
331
332     QVariantMap variantMap() const { return m_variantMap; }
333     void setVariantMap(const QVariantMap &variantMap) { m_variantMap = variantMap; }
334
335     int resettableProperty() const { return m_resetProperty; }
336     void setResettableProperty(int r) { m_resetProperty = r; }
337     void resetProperty() { m_resetProperty = 9; }
338
339     int propertyWithNotify() const { return m_propertyWithNotify; }
340     void setPropertyWithNotify(int i) { m_propertyWithNotify = i; emit oddlyNamedNotifySignal(); }
341
342     MyQmlObject *qmlObject() { return &m_qmlObject; }
343
344 signals:
345     void clicked();
346     void oddlyNamedNotifySignal();
347
348 private:
349     int m_resetProperty;
350     QRect m_rect;
351     QUrl m_url;
352     QVariantMap m_variantMap;
353     int m_propertyWithNotify;
354     MyQmlObject m_qmlObject;
355 };
356
357 QML_DECLARE_TYPE(PropertyObject);
358
359 void tst_qqmlproperty::qmlmetaproperty_object()
360 {
361     QObject object; // Has no default property
362     PropertyObject dobject; // Has default property
363
364     {
365         QQmlProperty prop(&object);
366
367         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
368         QVERIFY(binding != 0);
369         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
370         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
371         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
372
373         QObject *obj = new QObject;
374
375         QCOMPARE(prop.name(), QString());
376         QCOMPARE(prop.read(), QVariant());
377         QCOMPARE(prop.write(QVariant()), false);
378         QCOMPARE(prop.hasNotifySignal(), false);
379         QCOMPARE(prop.needsNotifySignal(), false);
380         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
381         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
382         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
383         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
384         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
385         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
386         QVERIFY(!prop.method().isValid());
387         QCOMPARE(prop.type(), QQmlProperty::Invalid);
388         QCOMPARE(prop.isProperty(), false);
389         QCOMPARE(prop.isWritable(), false);
390         QCOMPARE(prop.isDesignable(), false);
391         QCOMPARE(prop.isResettable(), false);
392         QCOMPARE(prop.isSignalProperty(), false);
393         QCOMPARE(prop.isValid(), false);
394         QCOMPARE(prop.object(), (QObject *)0);
395         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
396         QCOMPARE(prop.propertyType(), 0);
397         QCOMPARE(prop.propertyTypeName(), (const char *)0);
398         QVERIFY(prop.property().name() == 0);
399         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
400         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
401         QVERIFY(binding == 0);
402         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
403         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
404         QVERIFY(sigExprWatcher.wasDeleted());
405         QCOMPARE(prop.index(), -1);
406         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
407
408         delete obj;
409     }
410
411     {
412         QQmlProperty prop(&dobject);
413
414         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
415         static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
416         QVERIFY(binding != 0);
417         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
418         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
419         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
420
421         QObject *obj = new QObject;
422
423         QCOMPARE(prop.name(), QString("defaultProperty"));
424         QCOMPARE(prop.read(), QVariant(10));
425         QCOMPARE(prop.write(QVariant()), false);
426         QCOMPARE(prop.hasNotifySignal(), false);
427         QCOMPARE(prop.needsNotifySignal(), true);
428         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
429         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
430         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
431         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
432         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
433         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
434         QVERIFY(!prop.method().isValid());
435         QCOMPARE(prop.type(), QQmlProperty::Property);
436         QCOMPARE(prop.isProperty(), true);
437         QCOMPARE(prop.isWritable(), false);
438         QCOMPARE(prop.isDesignable(), true);
439         QCOMPARE(prop.isResettable(), false);
440         QCOMPARE(prop.isSignalProperty(), false);
441         QCOMPARE(prop.isValid(), true);
442         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
443         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::Normal);
444         QCOMPARE(prop.propertyType(), (int)QVariant::Int);
445         QCOMPARE(prop.propertyTypeName(), "int");
446         QCOMPARE(QString(prop.property().name()), QString("defaultProperty"));
447         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
448         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int");
449         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
450         QVERIFY(binding != 0);
451         QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data());
452         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
453         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
454         QVERIFY(sigExprWatcher.wasDeleted());
455         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
456         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
457
458         delete obj;
459     }
460 }
461
462 void tst_qqmlproperty::qmlmetaproperty_object_string()
463 {
464     QObject object; 
465     PropertyObject dobject; 
466
467     {
468         QQmlProperty prop(&object, QString("defaultProperty"));
469
470         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
471         QVERIFY(binding != 0);
472         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
473         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
474         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
475
476         QObject *obj = new QObject;
477
478         QCOMPARE(prop.name(), QString());
479         QCOMPARE(prop.read(), QVariant());
480         QCOMPARE(prop.write(QVariant()), false);
481         QCOMPARE(prop.hasNotifySignal(), false);
482         QCOMPARE(prop.needsNotifySignal(), false);
483         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
484         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
485         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
486         QCOMPARE(prop.connectNotifySignal(0, 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::Invalid);
491         QCOMPARE(prop.isProperty(), false);
492         QCOMPARE(prop.isWritable(), false);
493         QCOMPARE(prop.isDesignable(), false);
494         QCOMPARE(prop.isResettable(), false);
495         QCOMPARE(prop.isSignalProperty(), false);
496         QCOMPARE(prop.isValid(), false);
497         QCOMPARE(prop.object(), (QObject *)0);
498         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
499         QCOMPARE(prop.propertyType(), 0);
500         QCOMPARE(prop.propertyTypeName(), (const char *)0);
501         QVERIFY(prop.property().name() == 0);
502         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
503         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
504         QVERIFY(binding == 0);
505         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
506         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
507         QVERIFY(sigExprWatcher.wasDeleted());
508         QCOMPARE(prop.index(), -1);
509         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
510
511         delete obj;
512     }
513
514     {
515         QQmlProperty prop(&dobject, QString("defaultProperty"));
516
517         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
518         static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
519         QVERIFY(binding != 0);
520         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
521         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
522         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
523
524         QObject *obj = new QObject;
525
526         QCOMPARE(prop.name(), QString("defaultProperty"));
527         QCOMPARE(prop.read(), QVariant(10));
528         QCOMPARE(prop.write(QVariant()), false);
529         QCOMPARE(prop.hasNotifySignal(), false);
530         QCOMPARE(prop.needsNotifySignal(), true);
531         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
532         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
533         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
534         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
535         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
536         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
537         QVERIFY(!prop.method().isValid());
538         QCOMPARE(prop.type(), QQmlProperty::Property);
539         QCOMPARE(prop.isProperty(), true);
540         QCOMPARE(prop.isWritable(), false);
541         QCOMPARE(prop.isDesignable(), true);
542         QCOMPARE(prop.isResettable(), false);
543         QCOMPARE(prop.isSignalProperty(), false);
544         QCOMPARE(prop.isValid(), true);
545         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
546         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::Normal);
547         QCOMPARE(prop.propertyType(), (int)QVariant::Int);
548         QCOMPARE(prop.propertyTypeName(), "int");
549         QCOMPARE(QString(prop.property().name()), QString("defaultProperty"));
550         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
551         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int");
552         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
553         QVERIFY(binding != 0);
554         QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data());
555         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
556         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
557         QVERIFY(sigExprWatcher.wasDeleted());
558         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
559         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
560
561         delete obj;
562     }
563
564     {
565         QQmlProperty prop(&dobject, QString("onClicked"));
566
567         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
568         static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
569         QVERIFY(binding != 0);
570         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
571         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
572         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
573
574         QObject *obj = new QObject;
575
576         QCOMPARE(prop.name(), QString("onClicked"));
577         QCOMPARE(prop.read(), QVariant());
578         QCOMPARE(prop.write(QVariant("Hello")), false);
579         QCOMPARE(prop.hasNotifySignal(), false);
580         QCOMPARE(prop.needsNotifySignal(), false);
581         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
582         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
583         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
584         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
585         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
586         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
587         QCOMPARE(QString(prop.method().methodSignature()), QString("clicked()"));
588         QCOMPARE(prop.type(), QQmlProperty::SignalProperty);
589         QCOMPARE(prop.isProperty(), false);
590         QCOMPARE(prop.isWritable(), false);
591         QCOMPARE(prop.isDesignable(), false);
592         QCOMPARE(prop.isResettable(), false);
593         QCOMPARE(prop.isSignalProperty(), true);
594         QCOMPARE(prop.isValid(), true);
595         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
596         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
597         QCOMPARE(prop.propertyType(), 0);
598         QCOMPARE(prop.propertyTypeName(), (const char *)0);
599         QCOMPARE(prop.property().name(), (const char *)0);
600         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
601         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
602         QVERIFY(binding == 0);
603         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
604         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
605         QVERIFY(!sigExprWatcher.wasDeleted());
606         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr);
607         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()"));
608         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
609
610         delete obj;
611     }
612
613     {
614         QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"));
615
616         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
617         static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
618         QVERIFY(binding != 0);
619         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
620         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
621         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
622
623         QObject *obj = new QObject;
624
625         QCOMPARE(prop.name(), QString("onOddlyNamedNotifySignal"));
626         QCOMPARE(prop.read(), QVariant());
627         QCOMPARE(prop.write(QVariant("Hello")), false);
628         QCOMPARE(prop.hasNotifySignal(), false);
629         QCOMPARE(prop.needsNotifySignal(), false);
630         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
631         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
632         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
633         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
634         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
635         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
636         QCOMPARE(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()"));
637         QCOMPARE(prop.type(), QQmlProperty::SignalProperty);
638         QCOMPARE(prop.isProperty(), false);
639         QCOMPARE(prop.isWritable(), false);
640         QCOMPARE(prop.isDesignable(), false);
641         QCOMPARE(prop.isResettable(), false);
642         QCOMPARE(prop.isSignalProperty(), true);
643         QCOMPARE(prop.isValid(), true);
644         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
645         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
646         QCOMPARE(prop.propertyType(), 0);
647         QCOMPARE(prop.propertyTypeName(), (const char *)0);
648         QCOMPARE(prop.property().name(), (const char *)0);
649         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
650         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
651         QVERIFY(binding == 0);
652         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
653         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
654         QVERIFY(!sigExprWatcher.wasDeleted());
655         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr);
656         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()"));
657         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
658
659         delete obj;
660     }
661 }
662
663 void tst_qqmlproperty::qmlmetaproperty_object_context()
664 {
665     QObject object; // Has no default property
666     PropertyObject dobject; // Has default property
667
668     {
669         QQmlProperty prop(&object, engine.rootContext());
670
671         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
672         QVERIFY(binding != 0);
673         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
674         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
675         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
676
677         QObject *obj = new QObject;
678
679         QCOMPARE(prop.name(), QString());
680         QCOMPARE(prop.read(), QVariant());
681         QCOMPARE(prop.write(QVariant()), false);
682         QCOMPARE(prop.hasNotifySignal(), false);
683         QCOMPARE(prop.needsNotifySignal(), false);
684         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
685         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
686         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
687         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
688         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
689         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
690         QVERIFY(!prop.method().isValid());
691         QCOMPARE(prop.type(), QQmlProperty::Invalid);
692         QCOMPARE(prop.isProperty(), false);
693         QCOMPARE(prop.isWritable(), false);
694         QCOMPARE(prop.isDesignable(), false);
695         QCOMPARE(prop.isResettable(), false);
696         QCOMPARE(prop.isSignalProperty(), false);
697         QCOMPARE(prop.isValid(), false);
698         QCOMPARE(prop.object(), (QObject *)0);
699         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
700         QCOMPARE(prop.propertyType(), 0);
701         QCOMPARE(prop.propertyTypeName(), (const char *)0);
702         QVERIFY(prop.property().name() == 0);
703         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
704         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
705         QVERIFY(binding == 0);
706         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
707         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
708         QVERIFY(sigExprWatcher.wasDeleted());
709         QCOMPARE(prop.index(), -1);
710         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
711
712         delete obj;
713     }
714
715     {
716         QQmlProperty prop(&dobject, engine.rootContext());
717
718         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
719         static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
720         QVERIFY(binding != 0);
721         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
722         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
723         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
724
725         QObject *obj = new QObject;
726
727         QCOMPARE(prop.name(), QString("defaultProperty"));
728         QCOMPARE(prop.read(), QVariant(10));
729         QCOMPARE(prop.write(QVariant()), false);
730         QCOMPARE(prop.hasNotifySignal(), false);
731         QCOMPARE(prop.needsNotifySignal(), true);
732         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
733         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
734         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
735         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
736         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
737         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
738         QVERIFY(!prop.method().isValid());
739         QCOMPARE(prop.type(), QQmlProperty::Property);
740         QCOMPARE(prop.isProperty(), true);
741         QCOMPARE(prop.isWritable(), false);
742         QCOMPARE(prop.isDesignable(), true);
743         QCOMPARE(prop.isResettable(), false);
744         QCOMPARE(prop.isSignalProperty(), false);
745         QCOMPARE(prop.isValid(), true);
746         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
747         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::Normal);
748         QCOMPARE(prop.propertyType(), (int)QVariant::Int);
749         QCOMPARE(prop.propertyTypeName(), "int");
750         QCOMPARE(QString(prop.property().name()), QString("defaultProperty"));
751         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
752         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int");
753         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
754         QVERIFY(binding != 0);
755         QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data());
756         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
757         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
758         QVERIFY(sigExprWatcher.wasDeleted());
759         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
760         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
761
762         delete obj;
763     }
764 }
765
766 void tst_qqmlproperty::qmlmetaproperty_object_string_context()
767 {
768     QObject object; 
769     PropertyObject dobject; 
770
771     {
772         QQmlProperty prop(&object, QString("defaultProperty"), engine.rootContext());
773
774         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
775         QVERIFY(binding != 0);
776         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
777         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
778         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
779
780         QObject *obj = new QObject;
781
782         QCOMPARE(prop.name(), QString());
783         QCOMPARE(prop.read(), QVariant());
784         QCOMPARE(prop.write(QVariant()), false);
785         QCOMPARE(prop.hasNotifySignal(), false);
786         QCOMPARE(prop.needsNotifySignal(), false);
787         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
788         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
789         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
790         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
791         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
792         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
793         QVERIFY(!prop.method().isValid());
794         QCOMPARE(prop.type(), QQmlProperty::Invalid);
795         QCOMPARE(prop.isProperty(), false);
796         QCOMPARE(prop.isWritable(), false);
797         QCOMPARE(prop.isDesignable(), false);
798         QCOMPARE(prop.isResettable(), false);
799         QCOMPARE(prop.isSignalProperty(), false);
800         QCOMPARE(prop.isValid(), false);
801         QCOMPARE(prop.object(), (QObject *)0);
802         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
803         QCOMPARE(prop.propertyType(), 0);
804         QCOMPARE(prop.propertyTypeName(), (const char *)0);
805         QVERIFY(prop.property().name() == 0);
806         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
807         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
808         QVERIFY(binding == 0);
809         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
810         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
811         QVERIFY(sigExprWatcher.wasDeleted());
812         QCOMPARE(prop.index(), -1);
813         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
814
815         delete obj;
816     }
817
818     {
819         QQmlProperty prop(&dobject, QString("defaultProperty"), engine.rootContext());
820
821         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
822         static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
823         QVERIFY(binding != 0);
824         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
825         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
826         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
827
828         QObject *obj = new QObject;
829
830         QCOMPARE(prop.name(), QString("defaultProperty"));
831         QCOMPARE(prop.read(), QVariant(10));
832         QCOMPARE(prop.write(QVariant()), false);
833         QCOMPARE(prop.hasNotifySignal(), false);
834         QCOMPARE(prop.needsNotifySignal(), true);
835         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
836         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
837         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
838         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
839         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
840         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
841         QVERIFY(!prop.method().isValid());
842         QCOMPARE(prop.type(), QQmlProperty::Property);
843         QCOMPARE(prop.isProperty(), true);
844         QCOMPARE(prop.isWritable(), false);
845         QCOMPARE(prop.isDesignable(), true);
846         QCOMPARE(prop.isResettable(), false);
847         QCOMPARE(prop.isSignalProperty(), false);
848         QCOMPARE(prop.isValid(), true);
849         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
850         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::Normal);
851         QCOMPARE(prop.propertyType(), (int)QVariant::Int);
852         QCOMPARE(prop.propertyTypeName(), "int");
853         QCOMPARE(QString(prop.property().name()), QString("defaultProperty"));
854         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
855         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int");
856         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
857         QVERIFY(binding != 0);
858         QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data());
859         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
860         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
861         QVERIFY(sigExprWatcher.wasDeleted());
862         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
863         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
864
865         delete obj;
866     }
867
868     {
869         QQmlProperty prop(&dobject, QString("onClicked"), engine.rootContext());
870
871         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
872         static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
873         QVERIFY(binding != 0);
874         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
875         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
876         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
877
878         QObject *obj = new QObject;
879
880         QCOMPARE(prop.name(), QString("onClicked"));
881         QCOMPARE(prop.read(), QVariant());
882         QCOMPARE(prop.write(QVariant("Hello")), false);
883         QCOMPARE(prop.hasNotifySignal(), false);
884         QCOMPARE(prop.needsNotifySignal(), false);
885         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
886         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
887         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
888         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
889         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
890         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
891         QCOMPARE(QString(prop.method().methodSignature()), QString("clicked()"));
892         QCOMPARE(prop.type(), QQmlProperty::SignalProperty);
893         QCOMPARE(prop.isProperty(), false);
894         QCOMPARE(prop.isWritable(), false);
895         QCOMPARE(prop.isDesignable(), false);
896         QCOMPARE(prop.isResettable(), false);
897         QCOMPARE(prop.isSignalProperty(), true);
898         QCOMPARE(prop.isValid(), true);
899         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
900         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
901         QCOMPARE(prop.propertyType(), 0);
902         QCOMPARE(prop.propertyTypeName(), (const char *)0);
903         QCOMPARE(prop.property().name(), (const char *)0);
904         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
905         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
906         QVERIFY(binding == 0);
907         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
908         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
909         QVERIFY(!sigExprWatcher.wasDeleted());
910         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr);
911         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()"));
912         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
913
914         delete obj;
915     }
916
917     {
918         QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext());
919
920         QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
921         static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
922         QVERIFY(binding != 0);
923         QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
924         QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
925         QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
926
927         QObject *obj = new QObject;
928
929         QCOMPARE(prop.name(), QString("onOddlyNamedNotifySignal"));
930         QCOMPARE(prop.read(), QVariant());
931         QCOMPARE(prop.write(QVariant("Hello")), false);
932         QCOMPARE(prop.hasNotifySignal(), false);
933         QCOMPARE(prop.needsNotifySignal(), false);
934         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
935         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
936         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
937         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
938         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
939         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
940         QCOMPARE(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()"));
941         QCOMPARE(prop.type(), QQmlProperty::SignalProperty);
942         QCOMPARE(prop.isProperty(), false);
943         QCOMPARE(prop.isWritable(), false);
944         QCOMPARE(prop.isDesignable(), false);
945         QCOMPARE(prop.isResettable(), false);
946         QCOMPARE(prop.isSignalProperty(), true);
947         QCOMPARE(prop.isValid(), true);
948         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
949         QCOMPARE(prop.propertyTypeCategory(), QQmlProperty::InvalidCategory);
950         QCOMPARE(prop.propertyType(), 0);
951         QCOMPARE(prop.propertyTypeName(), (const char *)0);
952         QCOMPARE(prop.property().name(), (const char *)0);
953         QVERIFY(QQmlPropertyPrivate::binding(prop) == 0);
954         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
955         QVERIFY(binding == 0);
956         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
957         QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
958         QVERIFY(!sigExprWatcher.wasDeleted());
959         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr);
960         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()"));
961         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
962
963         delete obj;
964     }
965 }
966
967 void tst_qqmlproperty::name()
968 {
969     { 
970         QQmlProperty p;
971         QCOMPARE(p.name(), QString());
972     }
973
974     {
975         PropertyObject o;
976         QQmlProperty p(&o);
977         QCOMPARE(p.name(), QString("defaultProperty"));
978     }
979
980     {
981         QObject o;
982         QQmlProperty p(&o, QString("objectName"));
983         QCOMPARE(p.name(), QString("objectName"));
984     }
985
986     {
987         PropertyObject o;
988         QQmlProperty p(&o, "onClicked");
989         QCOMPARE(p.name(), QString("onClicked"));
990     }
991
992     {
993         QObject o;
994         QQmlProperty p(&o, "onClicked");
995         QCOMPARE(p.name(), QString());
996     }
997
998     {
999         PropertyObject o;
1000         QQmlProperty p(&o, "onPropertyWithNotifyChanged");
1001         QCOMPARE(p.name(), QString("onOddlyNamedNotifySignal"));
1002     }
1003
1004     {
1005         QObject o;
1006         QQmlProperty p(&o, "onPropertyWithNotifyChanged");
1007         QCOMPARE(p.name(), QString());
1008     }
1009
1010     {
1011         QObject o;
1012         QQmlProperty p(&o, "foo");
1013         QCOMPARE(p.name(), QString());
1014     }
1015
1016     {
1017         QQmlProperty p(0, "foo");
1018         QCOMPARE(p.name(), QString());
1019     }
1020
1021     {
1022         PropertyObject o;
1023         QQmlProperty p(&o, "rectProperty");
1024         QCOMPARE(p.name(), QString("rectProperty"));
1025     }
1026
1027     {
1028         PropertyObject o;
1029         QQmlProperty p(&o, "rectProperty.x");
1030         QCOMPARE(p.name(), QString("rectProperty.x"));
1031     }
1032
1033     {
1034         PropertyObject o;
1035         QQmlProperty p(&o, "rectProperty.foo");
1036         QCOMPARE(p.name(), QString());
1037     }
1038 }
1039
1040 void tst_qqmlproperty::read()
1041 {
1042     // Invalid 
1043     {
1044         QQmlProperty p;
1045         QCOMPARE(p.read(), QVariant());
1046     }
1047
1048     // Default prop
1049     {
1050         PropertyObject o;
1051         QQmlProperty p(&o);
1052         QCOMPARE(p.read(), QVariant(10));
1053     }
1054
1055     // Invalid default prop
1056     {
1057         QObject o;
1058         QQmlProperty p(&o);
1059         QCOMPARE(p.read(), QVariant());
1060     }
1061
1062     // Value prop by name
1063     {
1064         QObject o;
1065
1066         QQmlProperty p(&o, "objectName");
1067         QCOMPARE(p.read(), QVariant(QString()));
1068
1069         o.setObjectName("myName");
1070
1071         QCOMPARE(p.read(), QVariant("myName"));
1072     }
1073
1074     // Value prop by name (static)
1075     {
1076         QObject o;
1077
1078         QCOMPARE(QQmlProperty::read(&o, "objectName"), QVariant(QString()));
1079
1080         o.setObjectName("myName");
1081
1082         QCOMPARE(QQmlProperty::read(&o, "objectName"), QVariant("myName"));
1083     }
1084
1085     // Value-type prop
1086     {
1087         PropertyObject o;
1088         QQmlProperty p(&o, "rectProperty.x");
1089         QCOMPARE(p.read(), QVariant(10));
1090     }
1091
1092     // Invalid value-type prop
1093     {
1094         PropertyObject o;
1095         QQmlProperty p(&o, "rectProperty.foo");
1096         QCOMPARE(p.read(), QVariant());
1097     }
1098
1099     // Signal property
1100     {
1101         PropertyObject o;
1102         QQmlProperty p(&o, "onClicked");
1103         QCOMPARE(p.read(), QVariant());
1104
1105         QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1)));
1106         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
1107
1108         QCOMPARE(p.read(), QVariant());
1109     }
1110
1111     // Automatic signal property 
1112     {
1113         PropertyObject o;
1114         QQmlProperty p(&o, "onPropertyWithNotifyChanged");
1115         QCOMPARE(p.read(), QVariant());
1116
1117         QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1)));
1118         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
1119
1120         QCOMPARE(p.read(), QVariant());
1121     }
1122
1123     // Deleted object
1124     {
1125         PropertyObject *o = new PropertyObject;
1126         QQmlProperty p(o, "rectProperty.x");
1127         QCOMPARE(p.read(), QVariant(10));
1128         delete o;
1129         QCOMPARE(p.read(), QVariant());
1130     }
1131
1132     // Object property
1133     {
1134         PropertyObject o;
1135         QQmlProperty p(&o, "qmlObject");
1136         QCOMPARE(p.propertyTypeCategory(), QQmlProperty::Object);
1137         QCOMPARE(p.propertyType(), qMetaTypeId<MyQmlObject*>());
1138         QVariant v = p.read();
1139         QVERIFY(v.userType() == QMetaType::QObjectStar);
1140         QVERIFY(qvariant_cast<QObject *>(v) == o.qmlObject());
1141     }
1142     {
1143         QQmlComponent component(&engine, testFileUrl("readSynthesizedObject.qml"));
1144         QObject *object = component.create();
1145         QVERIFY(object != 0);
1146
1147         QQmlProperty p(object, "test", &engine);
1148
1149         QCOMPARE(p.propertyTypeCategory(), QQmlProperty::Object);
1150         QVERIFY(p.propertyType() != QMetaType::QObjectStar);
1151
1152         QVariant v = p.read();
1153         QVERIFY(v.userType() == QMetaType::QObjectStar);
1154         QCOMPARE(qvariant_cast<QObject *>(v)->property("a").toInt(), 10);
1155         QCOMPARE(qvariant_cast<QObject *>(v)->property("b").toInt(), 19);
1156     }
1157     {   // static
1158         QQmlComponent component(&engine, testFileUrl("readSynthesizedObject.qml"));
1159         QObject *object = component.create();
1160         QVERIFY(object != 0);
1161
1162         QVariant v = QQmlProperty::read(object, "test", &engine);
1163         QVERIFY(v.userType() == QMetaType::QObjectStar);
1164         QCOMPARE(qvariant_cast<QObject *>(v)->property("a").toInt(), 10);
1165         QCOMPARE(qvariant_cast<QObject *>(v)->property("b").toInt(), 19);
1166     }
1167
1168     // Attached property
1169     {
1170         QQmlComponent component(&engine);
1171         component.setData("import Test 1.0\nMyContainer { }", QUrl());
1172         QObject *object = component.create();
1173         QVERIFY(object != 0);
1174
1175         QQmlProperty p(object, "MyContainer.foo", qmlContext(object));
1176         QCOMPARE(p.read(), QVariant(13));
1177         delete object;
1178     }
1179     {
1180         QQmlComponent component(&engine);
1181         component.setData("import Test 1.0\nMyContainer { MyContainer.foo: 10 }", QUrl());
1182         QObject *object = component.create();
1183         QVERIFY(object != 0);
1184
1185         QQmlProperty p(object, "MyContainer.foo", qmlContext(object));
1186         QCOMPARE(p.read(), QVariant(10));
1187         delete object;
1188     }
1189     {
1190         QQmlComponent component(&engine);
1191         component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl());
1192         QObject *object = component.create();
1193         QVERIFY(object != 0);
1194
1195         QQmlProperty p(object, "Foo.MyContainer.foo", qmlContext(object));
1196         QCOMPARE(p.read(), QVariant(10));
1197         delete object;
1198     }
1199     {   // static
1200         QQmlComponent component(&engine);
1201         component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl());
1202         QObject *object = component.create();
1203         QVERIFY(object != 0);
1204
1205         QCOMPARE(QQmlProperty::read(object, "Foo.MyContainer.foo", qmlContext(object)), QVariant(10));
1206         delete object;
1207     }
1208 }
1209
1210 void tst_qqmlproperty::write()
1211 {
1212     // Invalid
1213     {
1214         QQmlProperty p;
1215         QCOMPARE(p.write(QVariant(10)), false);
1216     }
1217
1218     // Read-only default prop
1219     {
1220         PropertyObject o;
1221         QQmlProperty p(&o);
1222         QCOMPARE(p.write(QVariant(10)), false);
1223     }
1224
1225     // Invalid default prop
1226     {
1227         QObject o;
1228         QQmlProperty p(&o);
1229         QCOMPARE(p.write(QVariant(10)), false);
1230     }
1231
1232     // Read-only prop by name
1233     {
1234         PropertyObject o;
1235         QQmlProperty p(&o, QString("defaultProperty"));
1236         QCOMPARE(p.write(QVariant(10)), false);
1237     }
1238
1239     // Writable prop by name
1240     {
1241         PropertyObject o;
1242         QQmlProperty p(&o, QString("objectName"));
1243         QCOMPARE(o.objectName(), QString());
1244         QCOMPARE(p.write(QVariant(QString("myName"))), true);
1245         QCOMPARE(o.objectName(), QString("myName"));
1246     }
1247
1248     // Writable prop by name (static)
1249     {
1250         PropertyObject o;
1251         QCOMPARE(QQmlProperty::write(&o, QString("objectName"), QVariant(QString("myName"))), true);
1252         QCOMPARE(o.objectName(), QString("myName"));
1253     }
1254
1255     // Deleted object
1256     {
1257         PropertyObject *o = new PropertyObject;
1258         QQmlProperty p(o, QString("objectName"));
1259         QCOMPARE(p.write(QVariant(QString("myName"))), true);
1260         QCOMPARE(o->objectName(), QString("myName"));
1261
1262         delete o;
1263
1264         QCOMPARE(p.write(QVariant(QString("myName"))), false);
1265     }
1266
1267     // Signal property
1268     {
1269         PropertyObject o;
1270         QQmlProperty p(&o, "onClicked");
1271         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
1272
1273         QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1)));
1274         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
1275
1276         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
1277
1278         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
1279     }
1280
1281     // Automatic signal property
1282     {
1283         PropertyObject o;
1284         QQmlProperty p(&o, "onPropertyWithNotifyChanged");
1285         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
1286
1287         QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1)));
1288         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
1289
1290         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
1291
1292         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
1293     }
1294
1295     // Value-type property
1296     {
1297         PropertyObject o;
1298         QQmlProperty p(&o, "wrectProperty");
1299
1300         QCOMPARE(o.wrectProperty(), QRect());
1301         QCOMPARE(p.write(QRect(1, 13, 99, 8)), true);
1302         QCOMPARE(o.wrectProperty(), QRect(1, 13, 99, 8));
1303
1304         QQmlProperty p2(&o, "wrectProperty.x");
1305         QCOMPARE(p2.read(), QVariant(1));
1306         QCOMPARE(p2.write(QVariant(6)), true);
1307         QCOMPARE(p2.read(), QVariant(6));
1308         QCOMPARE(o.wrectProperty(), QRect(6, 13, 99, 8));
1309     }
1310
1311     // URL-property
1312     {
1313         PropertyObject o;
1314         QQmlProperty p(&o, "url");
1315
1316         QCOMPARE(p.write(QUrl("main.qml")), true);
1317         QCOMPARE(o.url(), QUrl("main.qml"));
1318
1319         QQmlProperty p2(&o, "url", engine.rootContext());
1320
1321         QUrl result = engine.baseUrl().resolved(QUrl("main.qml"));
1322         QVERIFY(result != QUrl("main.qml"));
1323
1324         QCOMPARE(p2.write(QUrl("main.qml")), true);
1325         QCOMPARE(o.url(), result);
1326     }
1327     {   // static
1328         PropertyObject o;
1329
1330         QCOMPARE(QQmlProperty::write(&o, "url", QUrl("main.qml")), true);
1331         QCOMPARE(o.url(), QUrl("main.qml"));
1332
1333         QUrl result = engine.baseUrl().resolved(QUrl("main.qml"));
1334         QVERIFY(result != QUrl("main.qml"));
1335
1336         QCOMPARE(QQmlProperty::write(&o, "url", QUrl("main.qml"), engine.rootContext()), true);
1337         QCOMPARE(o.url(), result);
1338     }
1339
1340     // VariantMap-property
1341     QVariantMap vm;
1342     vm.insert("key", "value");
1343
1344     {
1345         PropertyObject o;
1346         QQmlProperty p(&o, "variantMap");
1347
1348         QCOMPARE(p.write(vm), true);
1349         QCOMPARE(o.variantMap(), vm);
1350
1351         QQmlProperty p2(&o, "variantMap", engine.rootContext());
1352
1353         QCOMPARE(p2.write(vm), true);
1354         QCOMPARE(o.variantMap(), vm);
1355     }
1356     {   // static
1357         PropertyObject o;
1358
1359         QCOMPARE(QQmlProperty::write(&o, "variantMap", vm), true);
1360         QCOMPARE(o.variantMap(), vm);
1361
1362         QCOMPARE(QQmlProperty::write(&o, "variantMap", vm, engine.rootContext()), true);
1363         QCOMPARE(o.variantMap(), vm);
1364     }
1365
1366     // Attached property
1367     {
1368         QQmlComponent component(&engine);
1369         component.setData("import Test 1.0\nMyContainer { }", QUrl());
1370         QObject *object = component.create();
1371         QVERIFY(object != 0);
1372
1373         QQmlProperty p(object, "MyContainer.foo", qmlContext(object));
1374         p.write(QVariant(99));
1375         QCOMPARE(p.read(), QVariant(99));
1376         delete object;
1377     }
1378     {
1379         QQmlComponent component(&engine);
1380         component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl());
1381         QObject *object = component.create();
1382         QVERIFY(object != 0);
1383
1384         QQmlProperty p(object, "Foo.MyContainer.foo", qmlContext(object));
1385         p.write(QVariant(99));
1386         QCOMPARE(p.read(), QVariant(99));
1387         delete object;
1388     }
1389 }
1390
1391 void tst_qqmlproperty::reset()
1392 {
1393     // Invalid
1394     {
1395         QQmlProperty p;
1396         QCOMPARE(p.isResettable(), false);
1397         QCOMPARE(p.reset(), false);
1398     }
1399
1400     // Read-only default prop
1401     {
1402         PropertyObject o;
1403         QQmlProperty p(&o);
1404         QCOMPARE(p.isResettable(), false);
1405         QCOMPARE(p.reset(), false);
1406     }
1407
1408     // Invalid default prop
1409     {
1410         QObject o;
1411         QQmlProperty p(&o);
1412         QCOMPARE(p.isResettable(), false);
1413         QCOMPARE(p.reset(), false);
1414     }
1415
1416     // Non-resettable-only prop by name
1417     {
1418         PropertyObject o;
1419         QQmlProperty p(&o, QString("defaultProperty"));
1420         QCOMPARE(p.isResettable(), false);
1421         QCOMPARE(p.reset(), false);
1422     }
1423
1424     // Resettable prop by name
1425     {
1426         PropertyObject o;
1427         QQmlProperty p(&o, QString("resettableProperty"));
1428
1429         QCOMPARE(p.read(), QVariant(9));
1430         QCOMPARE(p.write(QVariant(11)), true);
1431         QCOMPARE(p.read(), QVariant(11));
1432
1433         QCOMPARE(p.isResettable(), true);
1434         QCOMPARE(p.reset(), true);
1435
1436         QCOMPARE(p.read(), QVariant(9));
1437     }
1438
1439     // Deleted object
1440     {
1441         PropertyObject *o = new PropertyObject;
1442
1443         QQmlProperty p(o, QString("resettableProperty"));
1444
1445         QCOMPARE(p.isResettable(), true);
1446         QCOMPARE(p.reset(), true);
1447
1448         delete o;
1449
1450         QCOMPARE(p.isResettable(), false);
1451         QCOMPARE(p.reset(), false);
1452     }
1453
1454     // Signal property
1455     {
1456         PropertyObject o;
1457         QQmlProperty p(&o, "onClicked");
1458
1459         QCOMPARE(p.isResettable(), false);
1460         QCOMPARE(p.reset(), false);
1461     }
1462
1463     // Automatic signal property
1464     {
1465         PropertyObject o;
1466         QQmlProperty p(&o, "onPropertyWithNotifyChanged");
1467
1468         QCOMPARE(p.isResettable(), false);
1469         QCOMPARE(p.reset(), false);
1470     }
1471 }
1472
1473 void tst_qqmlproperty::writeObjectToList()
1474 {
1475     QQmlComponent containerComponent(&engine);
1476     containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl());
1477     MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create());
1478     QVERIFY(container != 0);
1479     QQmlListReference list(container, "children");
1480     QVERIFY(list.count() == 1);
1481
1482     MyQmlObject *object = new MyQmlObject;
1483     QQmlProperty prop(container, "children");
1484     prop.write(qVariantFromValue(object));
1485     QCOMPARE(list.count(), 1);
1486     QCOMPARE(list.at(0), qobject_cast<QObject*>(object));
1487 }
1488
1489 void tst_qqmlproperty::writeListToList()
1490 {
1491     QQmlComponent containerComponent(&engine);
1492     containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl());
1493     MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create());
1494     QVERIFY(container != 0);
1495     QQmlListReference list(container, "children");
1496     QVERIFY(list.count() == 1);
1497
1498     QList<QObject*> objList;
1499     objList << new MyQmlObject() << new MyQmlObject() << new MyQmlObject() << new MyQmlObject();
1500     QQmlProperty prop(container, "children");
1501     prop.write(qVariantFromValue(objList));
1502     QCOMPARE(list.count(), 4);
1503
1504     //XXX need to try this with read/write prop (for read-only it correctly doesn't write)
1505     /*QList<MyQmlObject*> typedObjList;
1506     typedObjList << new MyQmlObject();
1507     prop.write(qVariantFromValue(&typedObjList));
1508     QCOMPARE(container->children()->size(), 1);*/
1509 }
1510
1511 void tst_qqmlproperty::urlHandling_data()
1512 {
1513     QTest::addColumn<QByteArray>("input");
1514     QTest::addColumn<QString>("scheme");
1515     QTest::addColumn<QString>("path");
1516     QTest::addColumn<QByteArray>("encoded");
1517
1518     QTest::newRow("unspecifiedFile")
1519         << QByteArray("main.qml")
1520         << QString("")
1521         << QString("main.qml")
1522         << QByteArray("main.qml");
1523
1524     QTest::newRow("specifiedFile")
1525         << QByteArray("file:///main.qml")
1526         << QString("file")
1527         << QString("/main.qml")
1528         << QByteArray("file:///main.qml");
1529
1530     QTest::newRow("httpFile")
1531         << QByteArray("http://www.example.com/main.qml")
1532         << QString("http")
1533         << QString("/main.qml")
1534         << QByteArray("http://www.example.com/main.qml");
1535
1536     QTest::newRow("pathFile")
1537         << QByteArray("http://www.example.com/resources/main.qml")
1538         << QString("http")
1539         << QString("/resources/main.qml")
1540         << QByteArray("http://www.example.com/resources/main.qml");
1541
1542     QTest::newRow("encodableName")
1543         << QByteArray("http://www.example.com/main file.qml")
1544         << QString("http")
1545         << QString("/main file.qml")
1546         << QByteArray("http://www.example.com/main%20file.qml");
1547
1548     QTest::newRow("preencodedName")
1549         << QByteArray("http://www.example.com/resources%7Cmain%20file.qml")
1550         << QString("http")
1551         << QString("/resources|main file.qml")
1552         << QByteArray("http://www.example.com/resources%7Cmain%20file.qml");
1553
1554     QTest::newRow("encodableQuery")
1555         << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now working?")
1556         << QString("http")
1557         << QString("/main.qml")
1558         << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working?");
1559
1560     QTest::newRow("preencodedQuery")
1561         << QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now working%3F")
1562         << QString("http")
1563         << QString("/main.qml")
1564         << QByteArray("http://www.example.com/main.qml?type=text%2Fqml&comment=now%20working%3F");
1565
1566     QTest::newRow("encodableFragment")
1567         << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000|volume+50%")
1568         << QString("http")
1569         << QString("/main.qml")
1570         << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7Cvolume+50%25");
1571
1572     QTest::newRow("improperlyEncodedFragment")
1573         << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7Cvolume%2B50%")
1574         << QString("http")
1575         << QString("/main.qml")
1576         << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%257Cvolume%252B50%25");
1577 }
1578
1579 void tst_qqmlproperty::urlHandling()
1580 {
1581     QFETCH(QByteArray, input);
1582     QFETCH(QString, scheme);
1583     QFETCH(QString, path);
1584     QFETCH(QByteArray, encoded);
1585
1586     QString inputString(QString::fromUtf8(input));
1587
1588     {
1589         PropertyObject o;
1590         QQmlProperty p(&o, "url");
1591
1592         // Test url written as QByteArray
1593         QCOMPARE(p.write(input), true);
1594         QUrl byteArrayResult(o.url());
1595
1596         QCOMPARE(byteArrayResult.scheme(), scheme);
1597         QCOMPARE(byteArrayResult.path(), path);
1598         QCOMPARE(byteArrayResult.toString(QUrl::FullyEncoded), QString::fromUtf8(encoded));
1599         QCOMPARE(byteArrayResult.toEncoded(), encoded);
1600     }
1601
1602     {
1603         PropertyObject o;
1604         QQmlProperty p(&o, "url");
1605
1606         // Test url written as QString
1607         QCOMPARE(p.write(inputString), true);
1608         QUrl stringResult(o.url());
1609
1610         QCOMPARE(stringResult.scheme(), scheme);
1611         QCOMPARE(stringResult.path(), path);
1612         QCOMPARE(stringResult.toString(QUrl::FullyEncoded), QString::fromUtf8(encoded));
1613         QCOMPARE(stringResult.toEncoded(), encoded);
1614     }
1615 }
1616
1617 void tst_qqmlproperty::variantMapHandling_data()
1618 {
1619     QTest::addColumn<QVariantMap>("vm");
1620
1621     // Object literals
1622     {
1623         QVariantMap m;
1624         QTest::newRow("{}") << m;
1625     }
1626     {
1627         QVariantMap m;
1628         m["a"] = QVariantMap();
1629         QTest::newRow("{ a:{} }") << m;
1630     }
1631     {
1632         QVariantMap m, m2;
1633         m2["b"] = 10;
1634         m2["c"] = 20;
1635         m["a"] = m2;
1636         QTest::newRow("{ a:{b:10, c:20} }") << m;
1637     }
1638     {
1639         QVariantMap m;
1640         m["a"] = 10;
1641         m["b"] = QVariantList() << 20 << 30;
1642         QTest::newRow("{ a:10, b:[20, 30]}") << m;
1643     }
1644
1645     // Cyclic objects
1646     {
1647         QVariantMap m;
1648         m["p"] = QVariantMap();
1649         QTest::newRow("var o={}; o.p=o") << m;
1650     }
1651     {
1652         QVariantMap m;
1653         m["p"] = 123;
1654         m["q"] = QVariantMap();
1655         QTest::newRow("var o={}; o.p=123; o.q=o") << m;
1656     }
1657 }
1658
1659 void tst_qqmlproperty::variantMapHandling()
1660 {
1661     QFETCH(QVariantMap, vm);
1662
1663     PropertyObject o;
1664     QQmlProperty p(&o, "variantMap");
1665
1666     QCOMPARE(p.write(vm), true);
1667     QCOMPARE(o.variantMap(), vm);
1668 }
1669
1670 void tst_qqmlproperty::crashOnValueProperty()
1671 {
1672     QQmlEngine *engine = new QQmlEngine;
1673     QQmlComponent component(engine);
1674
1675     component.setData("import Test 1.0\nPropertyObject { wrectProperty.x: 10 }", QUrl());
1676     PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
1677     QVERIFY(obj != 0);
1678
1679     QQmlProperty p(obj, "wrectProperty.x", qmlContext(obj));
1680     QCOMPARE(p.name(), QString("wrectProperty.x"));
1681
1682     QCOMPARE(p.read(), QVariant(10));
1683
1684     //don't crash once the engine is deleted
1685     delete engine;
1686     engine = 0;
1687
1688     QCOMPARE(p.propertyTypeName(), "int");
1689     QCOMPARE(p.read(), QVariant(10));
1690     p.write(QVariant(20));
1691     QCOMPARE(p.read(), QVariant(20));
1692 }
1693
1694 // QTBUG-13719
1695 void tst_qqmlproperty::aliasPropertyBindings()
1696 {
1697     QQmlComponent component(&engine, testFileUrl("aliasPropertyBindings.qml"));
1698
1699     QObject *object = component.create();
1700     QVERIFY(object != 0);
1701
1702     QCOMPARE(object->property("realProperty").toReal(), 90.);
1703     QCOMPARE(object->property("aliasProperty").toReal(), 90.);
1704
1705     object->setProperty("test", 10);
1706
1707     QCOMPARE(object->property("realProperty").toReal(), 110.);
1708     QCOMPARE(object->property("aliasProperty").toReal(), 110.);
1709
1710     QQmlProperty realProperty(object, QLatin1String("realProperty"));
1711     QQmlProperty aliasProperty(object, QLatin1String("aliasProperty"));
1712
1713     // Check there is a binding on these two properties
1714     QVERIFY(QQmlPropertyPrivate::binding(realProperty) != 0);
1715     QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != 0);
1716
1717     // Check that its the same binding on these two properties
1718     QCOMPARE(QQmlPropertyPrivate::binding(realProperty),
1719              QQmlPropertyPrivate::binding(aliasProperty));
1720
1721     // Change the binding
1722     object->setProperty("state", QString("switch"));
1723
1724     QVERIFY(QQmlPropertyPrivate::binding(realProperty) != 0);
1725     QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != 0);
1726     QCOMPARE(QQmlPropertyPrivate::binding(realProperty),
1727              QQmlPropertyPrivate::binding(aliasProperty));
1728
1729     QCOMPARE(object->property("realProperty").toReal(), 96.);
1730     QCOMPARE(object->property("aliasProperty").toReal(), 96.);
1731
1732     // Check the old binding really has not effect any more
1733     object->setProperty("test", 4);
1734
1735     QCOMPARE(object->property("realProperty").toReal(), 96.);
1736     QCOMPARE(object->property("aliasProperty").toReal(), 96.);
1737
1738     object->setProperty("test2", 9);
1739
1740     QCOMPARE(object->property("realProperty").toReal(), 288.);
1741     QCOMPARE(object->property("aliasProperty").toReal(), 288.);
1742
1743     // Revert
1744     object->setProperty("state", QString(""));
1745
1746     QVERIFY(QQmlPropertyPrivate::binding(realProperty) != 0);
1747     QVERIFY(QQmlPropertyPrivate::binding(aliasProperty) != 0);
1748     QCOMPARE(QQmlPropertyPrivate::binding(realProperty),
1749              QQmlPropertyPrivate::binding(aliasProperty));
1750
1751     QCOMPARE(object->property("realProperty").toReal(), 20.);
1752     QCOMPARE(object->property("aliasProperty").toReal(), 20.);
1753
1754     object->setProperty("test2", 3);
1755
1756     QCOMPARE(object->property("realProperty").toReal(), 20.);
1757     QCOMPARE(object->property("aliasProperty").toReal(), 20.);
1758
1759     delete object;
1760 }
1761
1762 void tst_qqmlproperty::copy()
1763 {
1764     PropertyObject object;
1765
1766     QQmlProperty *property = new QQmlProperty(&object, QLatin1String("defaultProperty"));
1767     QCOMPARE(property->name(), QString("defaultProperty"));
1768     QCOMPARE(property->read(), QVariant(10));
1769     QCOMPARE(property->type(), QQmlProperty::Property);
1770     QCOMPARE(property->propertyTypeCategory(), QQmlProperty::Normal);
1771     QCOMPARE(property->propertyType(), (int)QVariant::Int);
1772
1773     QQmlProperty p1(*property);
1774     QCOMPARE(p1.name(), QString("defaultProperty"));
1775     QCOMPARE(p1.read(), QVariant(10));
1776     QCOMPARE(p1.type(), QQmlProperty::Property);
1777     QCOMPARE(p1.propertyTypeCategory(), QQmlProperty::Normal);
1778     QCOMPARE(p1.propertyType(), (int)QVariant::Int);
1779
1780     QQmlProperty p2(&object, QLatin1String("url"));
1781     QCOMPARE(p2.name(), QString("url"));
1782     p2 = *property;
1783     QCOMPARE(p2.name(), QString("defaultProperty"));
1784     QCOMPARE(p2.read(), QVariant(10));
1785     QCOMPARE(p2.type(), QQmlProperty::Property);
1786     QCOMPARE(p2.propertyTypeCategory(), QQmlProperty::Normal);
1787     QCOMPARE(p2.propertyType(), (int)QVariant::Int);
1788
1789     delete property; property = 0;
1790
1791     QCOMPARE(p1.name(), QString("defaultProperty"));
1792     QCOMPARE(p1.read(), QVariant(10));
1793     QCOMPARE(p1.type(), QQmlProperty::Property);
1794     QCOMPARE(p1.propertyTypeCategory(), QQmlProperty::Normal);
1795     QCOMPARE(p1.propertyType(), (int)QVariant::Int);
1796
1797     QCOMPARE(p2.name(), QString("defaultProperty"));
1798     QCOMPARE(p2.read(), QVariant(10));
1799     QCOMPARE(p2.type(), QQmlProperty::Property);
1800     QCOMPARE(p2.propertyTypeCategory(), QQmlProperty::Normal);
1801     QCOMPARE(p2.propertyType(), (int)QVariant::Int);
1802 }
1803
1804 void tst_qqmlproperty::noContext()
1805 {
1806     QQmlComponent compA(&engine, testFileUrl("NoContextTypeA.qml"));
1807     QQmlComponent compB(&engine, testFileUrl("NoContextTypeB.qml"));
1808
1809     QObject *a = compA.create();
1810     QVERIFY(a != 0);
1811     QObject *b = compB.create();
1812     QVERIFY(b != 0);
1813
1814     QVERIFY(QQmlProperty::write(b, "myTypeA", QVariant::fromValue(a), &engine));
1815
1816     delete a;
1817     delete b;
1818 }
1819
1820 void tst_qqmlproperty::assignEmptyVariantMap()
1821 {
1822     PropertyObject o;
1823
1824     QVariantMap map;
1825     map.insert("key", "value");
1826     o.setVariantMap(map);
1827     QCOMPARE(o.variantMap().count(), 1);
1828     QCOMPARE(o.variantMap().isEmpty(), false);
1829
1830     QQmlContext context(&engine);
1831     context.setContextProperty("o", &o);
1832
1833     QQmlComponent component(&engine, testFileUrl("assignEmptyVariantMap.qml"));
1834     QObject *obj = component.create(&context);
1835     QVERIFY(obj);
1836
1837     QCOMPARE(o.variantMap().count(), 0);
1838     QCOMPARE(o.variantMap().isEmpty(), true);
1839
1840     delete obj;
1841 }
1842
1843 void tst_qqmlproperty::warnOnInvalidBinding()
1844 {
1845     QUrl testUrl(testFileUrl("invalidBinding.qml"));
1846     QString expectedWarning;
1847
1848     // V4 error message for property-to-property binding
1849     expectedWarning = testUrl.toString() + QString::fromLatin1(":6:36: Unable to assign QQuickText to QQuickRectangle");
1850     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
1851
1852     // V8 error message for function-to-property binding
1853     expectedWarning = testUrl.toString() + QString::fromLatin1(":7:36: Unable to assign QQuickText to QQuickRectangle");
1854     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
1855
1856     // V8 error message for invalid binding to anchor
1857     expectedWarning = testUrl.toString() + QString::fromLatin1(":14: Unable to assign QQuickItem_QML_7 to QQuickAnchorLine");
1858     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
1859
1860     QQmlComponent component(&engine, testUrl);
1861     QObject *obj = component.create();
1862     QVERIFY(obj);
1863     delete obj;
1864 }
1865
1866 void tst_qqmlproperty::initTestCase()
1867 {
1868     QQmlDataTest::initTestCase();
1869     qmlRegisterType<MyQmlObject>("Test",1,0,"MyQmlObject");
1870     qmlRegisterType<PropertyObject>("Test",1,0,"PropertyObject");
1871     qmlRegisterType<MyContainer>("Test",1,0,"MyContainer");
1872 }
1873
1874 QTEST_MAIN(tst_qqmlproperty)
1875
1876 #include "tst_qqmlproperty.moc"