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