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