Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativeproperty / tst_qdeclarativeproperty.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QtDeclarative/qdeclarativeengine.h>
43 #include <QtDeclarative/qdeclarativecomponent.h>
44 #include <QtDeclarative/qdeclarativeproperty.h>
45 #include <QtDeclarative/private/qdeclarativeproperty_p.h>
46 #include <private/qdeclarativebinding_p.h>
47 #include <QtGui/QLineEdit>
48 #include <QtCore/qfileinfo.h>
49 #include <QtCore/qdir.h>
50
51 #ifdef Q_OS_SYMBIAN
52 // In Symbian OS test data is located in applications private dir
53 #define SRCDIR "."
54 #endif
55
56 inline QUrl TEST_FILE(const QString &filename)
57 {
58     QFileInfo fileInfo(__FILE__);
59     return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath(QLatin1String("data/") + filename));
60 }
61
62 class MyQmlObject : public QObject
63 {
64     Q_OBJECT
65 public:
66     MyQmlObject() {}
67 };
68
69 QML_DECLARE_TYPE(MyQmlObject);
70
71 class MyAttached : public QObject
72 {
73     Q_OBJECT
74     Q_PROPERTY(int foo READ foo WRITE setFoo)
75 public:
76     MyAttached(QObject *parent) : QObject(parent), m_foo(13) {}
77
78     int foo() const { return m_foo; }
79     void setFoo(int f) { m_foo = f; }
80
81 private:
82     int m_foo;
83 };
84
85 class MyContainer : public QObject
86 {
87     Q_OBJECT
88     Q_PROPERTY(QDeclarativeListProperty<MyQmlObject> children READ children)
89 public:
90     MyContainer() {}
91
92     QDeclarativeListProperty<MyQmlObject> children() { return QDeclarativeListProperty<MyQmlObject>(this, m_children); }
93
94     static MyAttached *qmlAttachedProperties(QObject *o) {
95         return new MyAttached(o);
96     }
97
98 private:
99     QList<MyQmlObject*> m_children;
100 };
101
102 QML_DECLARE_TYPE(MyContainer);
103 QML_DECLARE_TYPEINFO(MyContainer, QML_HAS_ATTACHED_PROPERTIES)
104
105 class tst_qdeclarativeproperty : public QObject
106 {
107     Q_OBJECT
108 public:
109     tst_qdeclarativeproperty() {}
110
111 private slots:
112     void initTestCase();
113
114     // Constructors
115     void qmlmetaproperty();
116     void qmlmetaproperty_object();
117     void qmlmetaproperty_object_string();
118     void qmlmetaproperty_object_context();
119     void qmlmetaproperty_object_string_context();
120
121     // Methods
122     void name();
123     void read();
124     void write();
125     void reset();
126
127     // Functionality
128     void writeObjectToList();
129     void writeListToList();
130
131     //writeToReadOnly();
132
133     // Bugs
134     void crashOnValueProperty();
135     void aliasPropertyBindings();
136
137     void copy();
138 private:
139     QDeclarativeEngine engine;
140 };
141
142 void tst_qdeclarativeproperty::qmlmetaproperty()
143 {
144     QDeclarativeProperty prop;
145
146     QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
147     QVERIFY(binding != 0);
148     QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
149     QVERIFY(expression != 0);
150
151     QObject *obj = new QObject;
152
153     QCOMPARE(prop.name(), QString());
154     QCOMPARE(prop.read(), QVariant());
155     QCOMPARE(prop.write(QVariant()), false);
156     QCOMPARE(prop.hasNotifySignal(), false);
157     QCOMPARE(prop.needsNotifySignal(), false);
158     QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
159     QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
160     QCOMPARE(prop.connectNotifySignal(obj, 0), false);
161     QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
162     QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
163     QCOMPARE(prop.connectNotifySignal(obj, -1), false);
164     QVERIFY(prop.method().signature() == 0);
165     QCOMPARE(prop.type(), QDeclarativeProperty::Invalid);
166     QCOMPARE(prop.isProperty(), false);
167     QCOMPARE(prop.isWritable(), false);
168     QCOMPARE(prop.isDesignable(), false);
169     QCOMPARE(prop.isResettable(), false);
170     QCOMPARE(prop.isSignalProperty(), false);
171     QCOMPARE(prop.isValid(), false);
172     QCOMPARE(prop.object(), (QObject *)0);
173     QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory);
174     QCOMPARE(prop.propertyType(), 0);
175     QCOMPARE(prop.propertyTypeName(), (const char *)0);
176     QVERIFY(prop.property().name() == 0);
177     QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
178     QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
179     QVERIFY(binding == 0);
180     QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
181     QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
182     QVERIFY(expression == 0);
183     QCOMPARE(prop.index(), -1);
184     QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
185
186     delete obj;
187 }
188
189 class PropertyObject : public QObject
190 {
191     Q_OBJECT
192     Q_PROPERTY(int defaultProperty READ defaultProperty)
193     Q_PROPERTY(QRect rectProperty READ rectProperty)
194     Q_PROPERTY(QRect wrectProperty READ wrectProperty WRITE setWRectProperty)
195     Q_PROPERTY(QUrl url READ url WRITE setUrl)
196     Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty)
197     Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal)
198     Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject)
199
200     Q_CLASSINFO("DefaultProperty", "defaultProperty")
201 public:
202     PropertyObject() : m_resetProperty(9) {}
203
204     int defaultProperty() { return 10; }
205     QRect rectProperty() { return QRect(10, 10, 1, 209); }
206
207     QRect wrectProperty() { return m_rect; }
208     void setWRectProperty(const QRect &r) { m_rect = r; }
209
210     QUrl url() { return m_url; }
211     void setUrl(const QUrl &u) { m_url = u; }
212
213     int resettableProperty() const { return m_resetProperty; }
214     void setResettableProperty(int r) { m_resetProperty = r; }
215     void resetProperty() { m_resetProperty = 9; }
216
217     int propertyWithNotify() const { return m_propertyWithNotify; }
218     void setPropertyWithNotify(int i) { m_propertyWithNotify = i; emit oddlyNamedNotifySignal(); }
219
220     MyQmlObject *qmlObject() { return &m_qmlObject; }
221 signals:
222     void clicked();
223     void oddlyNamedNotifySignal();
224
225 private:
226     int m_resetProperty;
227     QRect m_rect;
228     QUrl m_url;
229     int m_propertyWithNotify;
230     MyQmlObject m_qmlObject;
231 };
232
233 QML_DECLARE_TYPE(PropertyObject);
234
235 void tst_qdeclarativeproperty::qmlmetaproperty_object()
236 {
237     QObject object; // Has no default property
238     PropertyObject dobject; // Has default property
239
240     {
241         QDeclarativeProperty prop(&object);
242
243         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
244         QVERIFY(binding != 0);
245         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
246         QVERIFY(expression != 0);
247
248         QObject *obj = new QObject;
249
250         QCOMPARE(prop.name(), QString());
251         QCOMPARE(prop.read(), QVariant());
252         QCOMPARE(prop.write(QVariant()), false);
253         QCOMPARE(prop.hasNotifySignal(), false);
254         QCOMPARE(prop.needsNotifySignal(), false);
255         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
256         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
257         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
258         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
259         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
260         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
261         QVERIFY(prop.method().signature() == 0);
262         QCOMPARE(prop.type(), QDeclarativeProperty::Invalid);
263         QCOMPARE(prop.isProperty(), false);
264         QCOMPARE(prop.isWritable(), false);
265         QCOMPARE(prop.isDesignable(), false);
266         QCOMPARE(prop.isResettable(), false);
267         QCOMPARE(prop.isSignalProperty(), false);
268         QCOMPARE(prop.isValid(), false);
269         QCOMPARE(prop.object(), (QObject *)0);
270         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory);
271         QCOMPARE(prop.propertyType(), 0);
272         QCOMPARE(prop.propertyTypeName(), (const char *)0);
273         QVERIFY(prop.property().name() == 0);
274         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
275         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
276         QVERIFY(binding == 0);
277         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
278         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
279         QVERIFY(expression == 0);
280         QCOMPARE(prop.index(), -1);
281         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
282
283         delete obj;
284     }
285
286     {
287         QDeclarativeProperty prop(&dobject);
288
289         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
290         binding.data()->setTarget(prop);
291         QVERIFY(binding != 0);
292         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
293         QVERIFY(expression != 0);
294
295         QObject *obj = new QObject;
296
297         QCOMPARE(prop.name(), QString("defaultProperty"));
298         QCOMPARE(prop.read(), QVariant(10));
299         QCOMPARE(prop.write(QVariant()), false);
300         QCOMPARE(prop.hasNotifySignal(), false);
301         QCOMPARE(prop.needsNotifySignal(), true);
302         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
303         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
304         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
305         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
306         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
307         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
308         QVERIFY(prop.method().signature() == 0);
309         QCOMPARE(prop.type(), QDeclarativeProperty::Property);
310         QCOMPARE(prop.isProperty(), true);
311         QCOMPARE(prop.isWritable(), false);
312         QCOMPARE(prop.isDesignable(), true);
313         QCOMPARE(prop.isResettable(), false);
314         QCOMPARE(prop.isSignalProperty(), false);
315         QCOMPARE(prop.isValid(), true);
316         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
317         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal);
318         QCOMPARE(prop.propertyType(), (int)QVariant::Int);
319         QCOMPARE(prop.propertyTypeName(), "int");
320         QCOMPARE(QString(prop.property().name()), QString("defaultProperty"));
321         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
322         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int");
323         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
324         QVERIFY(binding != 0);
325         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == binding.data());
326         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
327         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
328         QVERIFY(expression == 0);
329         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
330         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
331
332         delete obj;
333     }
334 }
335
336 void tst_qdeclarativeproperty::qmlmetaproperty_object_string()
337 {
338     QObject object; 
339     PropertyObject dobject; 
340
341     {
342         QDeclarativeProperty prop(&object, QString("defaultProperty"));
343
344         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
345         QVERIFY(binding != 0);
346         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
347         QVERIFY(expression != 0);
348
349         QObject *obj = new QObject;
350
351         QCOMPARE(prop.name(), QString());
352         QCOMPARE(prop.read(), QVariant());
353         QCOMPARE(prop.write(QVariant()), false);
354         QCOMPARE(prop.hasNotifySignal(), false);
355         QCOMPARE(prop.needsNotifySignal(), false);
356         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
357         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
358         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
359         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
360         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
361         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
362         QVERIFY(prop.method().signature() == 0);
363         QCOMPARE(prop.type(), QDeclarativeProperty::Invalid);
364         QCOMPARE(prop.isProperty(), false);
365         QCOMPARE(prop.isWritable(), false);
366         QCOMPARE(prop.isDesignable(), false);
367         QCOMPARE(prop.isResettable(), false);
368         QCOMPARE(prop.isSignalProperty(), false);
369         QCOMPARE(prop.isValid(), false);
370         QCOMPARE(prop.object(), (QObject *)0);
371         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory);
372         QCOMPARE(prop.propertyType(), 0);
373         QCOMPARE(prop.propertyTypeName(), (const char *)0);
374         QVERIFY(prop.property().name() == 0);
375         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
376         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
377         QVERIFY(binding == 0);
378         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
379         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
380         QVERIFY(expression == 0);
381         QCOMPARE(prop.index(), -1);
382         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
383
384         delete obj;
385     }
386
387     {
388         QDeclarativeProperty prop(&dobject, QString("defaultProperty"));
389
390         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
391         binding.data()->setTarget(prop);
392         QVERIFY(binding != 0);
393         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
394         QVERIFY(expression != 0);
395
396         QObject *obj = new QObject;
397
398         QCOMPARE(prop.name(), QString("defaultProperty"));
399         QCOMPARE(prop.read(), QVariant(10));
400         QCOMPARE(prop.write(QVariant()), false);
401         QCOMPARE(prop.hasNotifySignal(), false);
402         QCOMPARE(prop.needsNotifySignal(), true);
403         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
404         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
405         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
406         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
407         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
408         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
409         QVERIFY(prop.method().signature() == 0);
410         QCOMPARE(prop.type(), QDeclarativeProperty::Property);
411         QCOMPARE(prop.isProperty(), true);
412         QCOMPARE(prop.isWritable(), false);
413         QCOMPARE(prop.isDesignable(), true);
414         QCOMPARE(prop.isResettable(), false);
415         QCOMPARE(prop.isSignalProperty(), false);
416         QCOMPARE(prop.isValid(), true);
417         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
418         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal);
419         QCOMPARE(prop.propertyType(), (int)QVariant::Int);
420         QCOMPARE(prop.propertyTypeName(), "int");
421         QCOMPARE(QString(prop.property().name()), QString("defaultProperty"));
422         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
423         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int");
424         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
425         QVERIFY(binding != 0);
426         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == binding.data());
427         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
428         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
429         QVERIFY(expression == 0);
430         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
431         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
432
433         delete obj;
434     }
435
436     {
437         QDeclarativeProperty prop(&dobject, QString("onClicked"));
438
439         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
440         binding.data()->setTarget(prop);
441         QVERIFY(binding != 0);
442         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
443         QVERIFY(expression != 0);
444
445         QObject *obj = new QObject;
446
447         QCOMPARE(prop.name(), QString("onClicked"));
448         QCOMPARE(prop.read(), QVariant());
449         QCOMPARE(prop.write(QVariant("Hello")), false);
450         QCOMPARE(prop.hasNotifySignal(), false);
451         QCOMPARE(prop.needsNotifySignal(), false);
452         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
453         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
454         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
455         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
456         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
457         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
458         QCOMPARE(QString(prop.method().signature()), QString("clicked()"));
459         QCOMPARE(prop.type(), QDeclarativeProperty::SignalProperty);
460         QCOMPARE(prop.isProperty(), false);
461         QCOMPARE(prop.isWritable(), false);
462         QCOMPARE(prop.isDesignable(), false);
463         QCOMPARE(prop.isResettable(), false);
464         QCOMPARE(prop.isSignalProperty(), true);
465         QCOMPARE(prop.isValid(), true);
466         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
467         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory);
468         QCOMPARE(prop.propertyType(), 0);
469         QCOMPARE(prop.propertyTypeName(), (const char *)0);
470         QCOMPARE(prop.property().name(), (const char *)0);
471         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
472         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
473         QVERIFY(binding == 0);
474         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
475         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
476         QVERIFY(expression != 0);
477         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == expression.data());
478         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()"));
479         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
480
481         delete obj;
482     }
483
484     {
485         QDeclarativeProperty prop(&dobject, QString("onPropertyWithNotifyChanged"));
486
487         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
488         binding.data()->setTarget(prop);
489         QVERIFY(binding != 0);
490         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
491         QVERIFY(expression != 0);
492
493         QObject *obj = new QObject;
494
495         QCOMPARE(prop.name(), QString("onOddlyNamedNotifySignal"));
496         QCOMPARE(prop.read(), QVariant());
497         QCOMPARE(prop.write(QVariant("Hello")), false);
498         QCOMPARE(prop.hasNotifySignal(), false);
499         QCOMPARE(prop.needsNotifySignal(), false);
500         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
501         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
502         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
503         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
504         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
505         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
506         QCOMPARE(QString(prop.method().signature()), QString("oddlyNamedNotifySignal()"));
507         QCOMPARE(prop.type(), QDeclarativeProperty::SignalProperty);
508         QCOMPARE(prop.isProperty(), false);
509         QCOMPARE(prop.isWritable(), false);
510         QCOMPARE(prop.isDesignable(), false);
511         QCOMPARE(prop.isResettable(), false);
512         QCOMPARE(prop.isSignalProperty(), true);
513         QCOMPARE(prop.isValid(), true);
514         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
515         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory);
516         QCOMPARE(prop.propertyType(), 0);
517         QCOMPARE(prop.propertyTypeName(), (const char *)0);
518         QCOMPARE(prop.property().name(), (const char *)0);
519         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
520         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
521         QVERIFY(binding == 0);
522         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
523         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
524         QVERIFY(expression != 0);
525         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == expression.data());
526         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()"));
527         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
528
529         delete obj;
530     }
531 }
532
533 void tst_qdeclarativeproperty::qmlmetaproperty_object_context()
534 {
535     QObject object; // Has no default property
536     PropertyObject dobject; // Has default property
537
538     {
539         QDeclarativeProperty prop(&object, engine.rootContext());
540
541         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
542         QVERIFY(binding != 0);
543         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
544         QVERIFY(expression != 0);
545
546         QObject *obj = new QObject;
547
548         QCOMPARE(prop.name(), QString());
549         QCOMPARE(prop.read(), QVariant());
550         QCOMPARE(prop.write(QVariant()), false);
551         QCOMPARE(prop.hasNotifySignal(), false);
552         QCOMPARE(prop.needsNotifySignal(), false);
553         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
554         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
555         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
556         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
557         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
558         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
559         QVERIFY(prop.method().signature() == 0);
560         QCOMPARE(prop.type(), QDeclarativeProperty::Invalid);
561         QCOMPARE(prop.isProperty(), false);
562         QCOMPARE(prop.isWritable(), false);
563         QCOMPARE(prop.isDesignable(), false);
564         QCOMPARE(prop.isResettable(), false);
565         QCOMPARE(prop.isSignalProperty(), false);
566         QCOMPARE(prop.isValid(), false);
567         QCOMPARE(prop.object(), (QObject *)0);
568         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory);
569         QCOMPARE(prop.propertyType(), 0);
570         QCOMPARE(prop.propertyTypeName(), (const char *)0);
571         QVERIFY(prop.property().name() == 0);
572         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
573         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
574         QVERIFY(binding == 0);
575         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
576         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
577         QVERIFY(expression == 0);
578         QCOMPARE(prop.index(), -1);
579         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
580
581         delete obj;
582     }
583
584     {
585         QDeclarativeProperty prop(&dobject, engine.rootContext());
586
587         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
588         binding.data()->setTarget(prop);
589         QVERIFY(binding != 0);
590         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
591         QVERIFY(expression != 0);
592
593         QObject *obj = new QObject;
594
595         QCOMPARE(prop.name(), QString("defaultProperty"));
596         QCOMPARE(prop.read(), QVariant(10));
597         QCOMPARE(prop.write(QVariant()), false);
598         QCOMPARE(prop.hasNotifySignal(), false);
599         QCOMPARE(prop.needsNotifySignal(), true);
600         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
601         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
602         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
603         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
604         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
605         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
606         QVERIFY(prop.method().signature() == 0);
607         QCOMPARE(prop.type(), QDeclarativeProperty::Property);
608         QCOMPARE(prop.isProperty(), true);
609         QCOMPARE(prop.isWritable(), false);
610         QCOMPARE(prop.isDesignable(), true);
611         QCOMPARE(prop.isResettable(), false);
612         QCOMPARE(prop.isSignalProperty(), false);
613         QCOMPARE(prop.isValid(), true);
614         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
615         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal);
616         QCOMPARE(prop.propertyType(), (int)QVariant::Int);
617         QCOMPARE(prop.propertyTypeName(), "int");
618         QCOMPARE(QString(prop.property().name()), QString("defaultProperty"));
619         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
620         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int");
621         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
622         QVERIFY(binding != 0);
623         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == binding.data());
624         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
625         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
626         QVERIFY(expression == 0);
627         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
628         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
629
630         delete obj;
631     }
632 }
633
634 void tst_qdeclarativeproperty::qmlmetaproperty_object_string_context()
635 {
636     QObject object; 
637     PropertyObject dobject; 
638
639     {
640         QDeclarativeProperty prop(&object, QString("defaultProperty"), engine.rootContext());
641
642         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
643         QVERIFY(binding != 0);
644         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
645         QVERIFY(expression != 0);
646
647         QObject *obj = new QObject;
648
649         QCOMPARE(prop.name(), QString());
650         QCOMPARE(prop.read(), QVariant());
651         QCOMPARE(prop.write(QVariant()), false);
652         QCOMPARE(prop.hasNotifySignal(), false);
653         QCOMPARE(prop.needsNotifySignal(), false);
654         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
655         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
656         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
657         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
658         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
659         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
660         QVERIFY(prop.method().signature() == 0);
661         QCOMPARE(prop.type(), QDeclarativeProperty::Invalid);
662         QCOMPARE(prop.isProperty(), false);
663         QCOMPARE(prop.isWritable(), false);
664         QCOMPARE(prop.isDesignable(), false);
665         QCOMPARE(prop.isResettable(), false);
666         QCOMPARE(prop.isSignalProperty(), false);
667         QCOMPARE(prop.isValid(), false);
668         QCOMPARE(prop.object(), (QObject *)0);
669         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory);
670         QCOMPARE(prop.propertyType(), 0);
671         QCOMPARE(prop.propertyTypeName(), (const char *)0);
672         QVERIFY(prop.property().name() == 0);
673         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
674         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
675         QVERIFY(binding == 0);
676         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
677         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
678         QVERIFY(expression == 0);
679         QCOMPARE(prop.index(), -1);
680         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
681
682         delete obj;
683     }
684
685     {
686         QDeclarativeProperty prop(&dobject, QString("defaultProperty"), engine.rootContext());
687
688         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
689         binding.data()->setTarget(prop);
690         QVERIFY(binding != 0);
691         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
692         QVERIFY(expression != 0);
693
694         QObject *obj = new QObject;
695
696         QCOMPARE(prop.name(), QString("defaultProperty"));
697         QCOMPARE(prop.read(), QVariant(10));
698         QCOMPARE(prop.write(QVariant()), false);
699         QCOMPARE(prop.hasNotifySignal(), false);
700         QCOMPARE(prop.needsNotifySignal(), true);
701         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
702         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
703         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
704         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
705         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
706         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
707         QVERIFY(prop.method().signature() == 0);
708         QCOMPARE(prop.type(), QDeclarativeProperty::Property);
709         QCOMPARE(prop.isProperty(), true);
710         QCOMPARE(prop.isWritable(), false);
711         QCOMPARE(prop.isDesignable(), true);
712         QCOMPARE(prop.isResettable(), false);
713         QCOMPARE(prop.isSignalProperty(), false);
714         QCOMPARE(prop.isValid(), true);
715         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
716         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal);
717         QCOMPARE(prop.propertyType(), (int)QVariant::Int);
718         QCOMPARE(prop.propertyTypeName(), "int");
719         QCOMPARE(QString(prop.property().name()), QString("defaultProperty"));
720         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
721         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Unable to assign null to int");
722         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
723         QVERIFY(binding != 0);
724         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == binding.data());
725         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
726         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
727         QVERIFY(expression == 0);
728         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
729         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
730
731         delete obj;
732     }
733
734     {
735         QDeclarativeProperty prop(&dobject, QString("onClicked"), engine.rootContext());
736
737         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
738         binding.data()->setTarget(prop);
739         QVERIFY(binding != 0);
740         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
741         QVERIFY(expression != 0);
742
743         QObject *obj = new QObject;
744
745         QCOMPARE(prop.name(), QString("onClicked"));
746         QCOMPARE(prop.read(), QVariant());
747         QCOMPARE(prop.write(QVariant("Hello")), false);
748         QCOMPARE(prop.hasNotifySignal(), false);
749         QCOMPARE(prop.needsNotifySignal(), false);
750         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
751         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
752         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
753         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
754         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
755         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
756         QCOMPARE(QString(prop.method().signature()), QString("clicked()"));
757         QCOMPARE(prop.type(), QDeclarativeProperty::SignalProperty);
758         QCOMPARE(prop.isProperty(), false);
759         QCOMPARE(prop.isWritable(), false);
760         QCOMPARE(prop.isDesignable(), false);
761         QCOMPARE(prop.isResettable(), false);
762         QCOMPARE(prop.isSignalProperty(), true);
763         QCOMPARE(prop.isValid(), true);
764         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
765         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory);
766         QCOMPARE(prop.propertyType(), 0);
767         QCOMPARE(prop.propertyTypeName(), (const char *)0);
768         QCOMPARE(prop.property().name(), (const char *)0);
769         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
770         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
771         QVERIFY(binding == 0);
772         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
773         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
774         QVERIFY(expression != 0);
775         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == expression.data());
776         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()"));
777         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
778
779         delete obj;
780     }
781
782     {
783         QDeclarativeProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext());
784
785         QWeakPointer<QDeclarativeBinding> binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext()));
786         binding.data()->setTarget(prop);
787         QVERIFY(binding != 0);
788         QWeakPointer<QDeclarativeExpression> expression(new QDeclarativeExpression());
789         QVERIFY(expression != 0);
790
791         QObject *obj = new QObject;
792
793         QCOMPARE(prop.name(), QString("onOddlyNamedNotifySignal"));
794         QCOMPARE(prop.read(), QVariant());
795         QCOMPARE(prop.write(QVariant("Hello")), false);
796         QCOMPARE(prop.hasNotifySignal(), false);
797         QCOMPARE(prop.needsNotifySignal(), false);
798         QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false);
799         QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false);
800         QCOMPARE(prop.connectNotifySignal(obj, 0), false);
801         QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false);
802         QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false);
803         QCOMPARE(prop.connectNotifySignal(obj, -1), false);
804         QCOMPARE(QString(prop.method().signature()), QString("oddlyNamedNotifySignal()"));
805         QCOMPARE(prop.type(), QDeclarativeProperty::SignalProperty);
806         QCOMPARE(prop.isProperty(), false);
807         QCOMPARE(prop.isWritable(), false);
808         QCOMPARE(prop.isDesignable(), false);
809         QCOMPARE(prop.isResettable(), false);
810         QCOMPARE(prop.isSignalProperty(), true);
811         QCOMPARE(prop.isValid(), true);
812         QCOMPARE(prop.object(), qobject_cast<QObject*>(&dobject));
813         QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory);
814         QCOMPARE(prop.propertyType(), 0);
815         QCOMPARE(prop.propertyTypeName(), (const char *)0);
816         QCOMPARE(prop.property().name(), (const char *)0);
817         QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0);
818         QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0);
819         QVERIFY(binding == 0);
820         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0);
821         QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
822         QVERIFY(expression != 0);
823         QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == expression.data());
824         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()"));
825         QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1);
826
827         delete obj;
828     }
829 }
830
831 void tst_qdeclarativeproperty::name()
832 {
833     { 
834         QDeclarativeProperty p;
835         QCOMPARE(p.name(), QString());
836     }
837
838     {
839         PropertyObject o;
840         QDeclarativeProperty p(&o);
841         QCOMPARE(p.name(), QString("defaultProperty"));
842     }
843
844     {
845         QObject o;
846         QDeclarativeProperty p(&o, QString("objectName"));
847         QCOMPARE(p.name(), QString("objectName"));
848     }
849
850     {
851         PropertyObject o;
852         QDeclarativeProperty p(&o, "onClicked");
853         QCOMPARE(p.name(), QString("onClicked"));
854     }
855
856     {
857         QObject o;
858         QDeclarativeProperty p(&o, "onClicked");
859         QCOMPARE(p.name(), QString());
860     }
861
862     {
863         PropertyObject o;
864         QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged");
865         QCOMPARE(p.name(), QString("onOddlyNamedNotifySignal"));
866     }
867
868     {
869         QObject o;
870         QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged");
871         QCOMPARE(p.name(), QString());
872     }
873
874     {
875         QObject o;
876         QDeclarativeProperty p(&o, "foo");
877         QCOMPARE(p.name(), QString());
878     }
879
880     {
881         QDeclarativeProperty p(0, "foo");
882         QCOMPARE(p.name(), QString());
883     }
884
885     {
886         PropertyObject o;
887         QDeclarativeProperty p(&o, "rectProperty");
888         QCOMPARE(p.name(), QString("rectProperty"));
889     }
890
891     {
892         PropertyObject o;
893         QDeclarativeProperty p(&o, "rectProperty.x");
894         QCOMPARE(p.name(), QString("rectProperty.x"));
895     }
896
897     {
898         PropertyObject o;
899         QDeclarativeProperty p(&o, "rectProperty.foo");
900         QCOMPARE(p.name(), QString());
901     }
902 }
903
904 void tst_qdeclarativeproperty::read()
905 {
906     // Invalid 
907     {
908         QDeclarativeProperty p;
909         QCOMPARE(p.read(), QVariant());
910     }
911
912     // Default prop
913     {
914         PropertyObject o;
915         QDeclarativeProperty p(&o);
916         QCOMPARE(p.read(), QVariant(10));
917     }
918
919     // Invalid default prop
920     {
921         QObject o;
922         QDeclarativeProperty p(&o);
923         QCOMPARE(p.read(), QVariant());
924     }
925
926     // Value prop by name
927     {
928         QObject o;
929
930         QDeclarativeProperty p(&o, "objectName");
931         QCOMPARE(p.read(), QVariant(QString()));
932
933         o.setObjectName("myName");
934
935         QCOMPARE(p.read(), QVariant("myName"));
936     }
937
938     // Value prop by name (static)
939     {
940         QObject o;
941
942         QCOMPARE(QDeclarativeProperty::read(&o, "objectName"), QVariant(QString()));
943
944         o.setObjectName("myName");
945
946         QCOMPARE(QDeclarativeProperty::read(&o, "objectName"), QVariant("myName"));
947     }
948
949     // Value-type prop
950     {
951         PropertyObject o;
952         QDeclarativeProperty p(&o, "rectProperty.x");
953         QCOMPARE(p.read(), QVariant(10));
954     }
955
956     // Invalid value-type prop
957     {
958         PropertyObject o;
959         QDeclarativeProperty p(&o, "rectProperty.foo");
960         QCOMPARE(p.read(), QVariant());
961     }
962
963     // Signal property
964     {
965         PropertyObject o;
966         QDeclarativeProperty p(&o, "onClicked");
967         QCOMPARE(p.read(), QVariant());
968
969         QVERIFY(0 == QDeclarativePropertyPrivate::setSignalExpression(p, new QDeclarativeExpression()));
970         QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p));
971
972         QCOMPARE(p.read(), QVariant());
973     }
974
975     // Automatic signal property 
976     {
977         PropertyObject o;
978         QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged");
979         QCOMPARE(p.read(), QVariant());
980
981         QVERIFY(0 == QDeclarativePropertyPrivate::setSignalExpression(p, new QDeclarativeExpression()));
982         QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p));
983
984         QCOMPARE(p.read(), QVariant());
985     }
986
987     // Deleted object
988     {
989         PropertyObject *o = new PropertyObject;
990         QDeclarativeProperty p(o, "rectProperty.x");
991         QCOMPARE(p.read(), QVariant(10));
992         delete o;
993         QCOMPARE(p.read(), QVariant());
994     }
995
996     // Object property
997     {
998         PropertyObject o;
999         QDeclarativeProperty p(&o, "qmlObject");
1000         QCOMPARE(p.propertyTypeCategory(), QDeclarativeProperty::Object);
1001         QCOMPARE(p.propertyType(), qMetaTypeId<MyQmlObject*>());
1002         QVariant v = p.read();
1003         QVERIFY(v.userType() == QMetaType::QObjectStar);
1004         QVERIFY(qvariant_cast<QObject *>(v) == o.qmlObject());
1005     }
1006     {
1007         QDeclarativeComponent component(&engine, TEST_FILE("readSynthesizedObject.qml"));
1008         QObject *object = component.create();
1009         QVERIFY(object != 0);
1010
1011         QDeclarativeProperty p(object, "test", &engine);
1012
1013         QCOMPARE(p.propertyTypeCategory(), QDeclarativeProperty::Object);
1014         QVERIFY(p.propertyType() != QMetaType::QObjectStar);
1015
1016         QVariant v = p.read();
1017         QVERIFY(v.userType() == QMetaType::QObjectStar);
1018         QCOMPARE(qvariant_cast<QObject *>(v)->property("a").toInt(), 10);
1019         QCOMPARE(qvariant_cast<QObject *>(v)->property("b").toInt(), 19);
1020     }
1021     {   // static
1022         QDeclarativeComponent component(&engine, TEST_FILE("readSynthesizedObject.qml"));
1023         QObject *object = component.create();
1024         QVERIFY(object != 0);
1025
1026         QVariant v = QDeclarativeProperty::read(object, "test", &engine);
1027         QVERIFY(v.userType() == QMetaType::QObjectStar);
1028         QCOMPARE(qvariant_cast<QObject *>(v)->property("a").toInt(), 10);
1029         QCOMPARE(qvariant_cast<QObject *>(v)->property("b").toInt(), 19);
1030     }
1031
1032     // Attached property
1033     {
1034         QDeclarativeComponent component(&engine);
1035         component.setData("import Test 1.0\nMyContainer { }", QUrl());
1036         QObject *object = component.create();
1037         QVERIFY(object != 0);
1038
1039         QDeclarativeProperty p(object, "MyContainer.foo", qmlContext(object));
1040         QCOMPARE(p.read(), QVariant(13));
1041         delete object;
1042     }
1043     {
1044         QDeclarativeComponent component(&engine);
1045         component.setData("import Test 1.0\nMyContainer { MyContainer.foo: 10 }", QUrl());
1046         QObject *object = component.create();
1047         QVERIFY(object != 0);
1048
1049         QDeclarativeProperty p(object, "MyContainer.foo", qmlContext(object));
1050         QCOMPARE(p.read(), QVariant(10));
1051         delete object;
1052     }
1053     {
1054         QDeclarativeComponent component(&engine);
1055         component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl());
1056         QObject *object = component.create();
1057         QVERIFY(object != 0);
1058
1059         QDeclarativeProperty p(object, "Foo.MyContainer.foo", qmlContext(object));
1060         QCOMPARE(p.read(), QVariant(10));
1061         delete object;
1062     }
1063     {   // static
1064         QDeclarativeComponent component(&engine);
1065         component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl());
1066         QObject *object = component.create();
1067         QVERIFY(object != 0);
1068
1069         QCOMPARE(QDeclarativeProperty::read(object, "Foo.MyContainer.foo", qmlContext(object)), QVariant(10));
1070         delete object;
1071     }
1072 }
1073
1074 void tst_qdeclarativeproperty::write()
1075 {
1076     // Invalid
1077     {
1078         QDeclarativeProperty p;
1079         QCOMPARE(p.write(QVariant(10)), false);
1080     }
1081
1082     // Read-only default prop
1083     {
1084         PropertyObject o;
1085         QDeclarativeProperty p(&o);
1086         QCOMPARE(p.write(QVariant(10)), false);
1087     }
1088
1089     // Invalid default prop
1090     {
1091         QObject o;
1092         QDeclarativeProperty p(&o);
1093         QCOMPARE(p.write(QVariant(10)), false);
1094     }
1095
1096     // Read-only prop by name
1097     {
1098         PropertyObject o;
1099         QDeclarativeProperty p(&o, QString("defaultProperty"));
1100         QCOMPARE(p.write(QVariant(10)), false);
1101     }
1102
1103     // Writable prop by name
1104     {
1105         PropertyObject o;
1106         QDeclarativeProperty p(&o, QString("objectName"));
1107         QCOMPARE(o.objectName(), QString());
1108         QCOMPARE(p.write(QVariant(QString("myName"))), true);
1109         QCOMPARE(o.objectName(), QString("myName"));
1110     }
1111
1112     // Writable prop by name (static)
1113     {
1114         PropertyObject o;
1115         QCOMPARE(QDeclarativeProperty::write(&o, QString("objectName"), QVariant(QString("myName"))), true);
1116         QCOMPARE(o.objectName(), QString("myName"));
1117     }
1118
1119     // Deleted object
1120     {
1121         PropertyObject *o = new PropertyObject;
1122         QDeclarativeProperty p(o, QString("objectName"));
1123         QCOMPARE(p.write(QVariant(QString("myName"))), true);
1124         QCOMPARE(o->objectName(), QString("myName"));
1125
1126         delete o;
1127
1128         QCOMPARE(p.write(QVariant(QString("myName"))), false);
1129     }
1130
1131     // Signal property
1132     {
1133         PropertyObject o;
1134         QDeclarativeProperty p(&o, "onClicked");
1135         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
1136
1137         QVERIFY(0 == QDeclarativePropertyPrivate::setSignalExpression(p, new QDeclarativeExpression()));
1138         QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p));
1139
1140         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
1141
1142         QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p));
1143     }
1144
1145     // Automatic signal property
1146     {
1147         PropertyObject o;
1148         QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged");
1149         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
1150
1151         QVERIFY(0 == QDeclarativePropertyPrivate::setSignalExpression(p, new QDeclarativeExpression()));
1152         QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p));
1153
1154         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
1155
1156         QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p));
1157     }
1158
1159     // Value-type property
1160     {
1161         PropertyObject o;
1162         QDeclarativeProperty p(&o, "wrectProperty");
1163
1164         QCOMPARE(o.wrectProperty(), QRect());
1165         QCOMPARE(p.write(QRect(1, 13, 99, 8)), true);
1166         QCOMPARE(o.wrectProperty(), QRect(1, 13, 99, 8));
1167
1168         QDeclarativeProperty p2(&o, "wrectProperty.x");
1169         QCOMPARE(p2.read(), QVariant(1));
1170         QCOMPARE(p2.write(QVariant(6)), true);
1171         QCOMPARE(p2.read(), QVariant(6));
1172         QCOMPARE(o.wrectProperty(), QRect(6, 13, 99, 8));
1173     }
1174
1175     // URL-property
1176     {
1177         PropertyObject o;
1178         QDeclarativeProperty p(&o, "url");
1179
1180         QCOMPARE(p.write(QUrl("main.qml")), true);
1181         QCOMPARE(o.url(), QUrl("main.qml"));
1182
1183         QDeclarativeProperty p2(&o, "url", engine.rootContext());
1184
1185         QUrl result = engine.baseUrl().resolved(QUrl("main.qml"));
1186         QVERIFY(result != QUrl("main.qml"));
1187
1188         QCOMPARE(p2.write(QUrl("main.qml")), true);
1189         QCOMPARE(o.url(), result);
1190     }
1191     {   // static
1192         PropertyObject o;
1193
1194         QCOMPARE(QDeclarativeProperty::write(&o, "url", QUrl("main.qml")), true);
1195         QCOMPARE(o.url(), QUrl("main.qml"));
1196
1197         QUrl result = engine.baseUrl().resolved(QUrl("main.qml"));
1198         QVERIFY(result != QUrl("main.qml"));
1199
1200         QCOMPARE(QDeclarativeProperty::write(&o, "url", QUrl("main.qml"), engine.rootContext()), true);
1201         QCOMPARE(o.url(), result);
1202     }
1203
1204     // Attached property
1205     {
1206         QDeclarativeComponent component(&engine);
1207         component.setData("import Test 1.0\nMyContainer { }", QUrl());
1208         QObject *object = component.create();
1209         QVERIFY(object != 0);
1210
1211         QDeclarativeProperty p(object, "MyContainer.foo", qmlContext(object));
1212         p.write(QVariant(99));
1213         QCOMPARE(p.read(), QVariant(99));
1214         delete object;
1215     }
1216     {
1217         QDeclarativeComponent component(&engine);
1218         component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl());
1219         QObject *object = component.create();
1220         QVERIFY(object != 0);
1221
1222         QDeclarativeProperty p(object, "Foo.MyContainer.foo", qmlContext(object));
1223         p.write(QVariant(99));
1224         QCOMPARE(p.read(), QVariant(99));
1225         delete object;
1226     }
1227 }
1228
1229 void tst_qdeclarativeproperty::reset()
1230 {
1231     // Invalid
1232     {
1233         QDeclarativeProperty p;
1234         QCOMPARE(p.isResettable(), false);
1235         QCOMPARE(p.reset(), false);
1236     }
1237
1238     // Read-only default prop
1239     {
1240         PropertyObject o;
1241         QDeclarativeProperty p(&o);
1242         QCOMPARE(p.isResettable(), false);
1243         QCOMPARE(p.reset(), false);
1244     }
1245
1246     // Invalid default prop
1247     {
1248         QObject o;
1249         QDeclarativeProperty p(&o);
1250         QCOMPARE(p.isResettable(), false);
1251         QCOMPARE(p.reset(), false);
1252     }
1253
1254     // Non-resettable-only prop by name
1255     {
1256         PropertyObject o;
1257         QDeclarativeProperty p(&o, QString("defaultProperty"));
1258         QCOMPARE(p.isResettable(), false);
1259         QCOMPARE(p.reset(), false);
1260     }
1261
1262     // Resettable prop by name
1263     {
1264         PropertyObject o;
1265         QDeclarativeProperty p(&o, QString("resettableProperty"));
1266
1267         QCOMPARE(p.read(), QVariant(9));
1268         QCOMPARE(p.write(QVariant(11)), true);
1269         QCOMPARE(p.read(), QVariant(11));
1270
1271         QCOMPARE(p.isResettable(), true);
1272         QCOMPARE(p.reset(), true);
1273
1274         QCOMPARE(p.read(), QVariant(9));
1275     }
1276
1277     // Deleted object
1278     {
1279         PropertyObject *o = new PropertyObject;
1280
1281         QDeclarativeProperty p(o, QString("resettableProperty"));
1282
1283         QCOMPARE(p.isResettable(), true);
1284         QCOMPARE(p.reset(), true);
1285
1286         delete o;
1287
1288         QCOMPARE(p.isResettable(), false);
1289         QCOMPARE(p.reset(), false);
1290     }
1291
1292     // Signal property
1293     {
1294         PropertyObject o;
1295         QDeclarativeProperty p(&o, "onClicked");
1296
1297         QCOMPARE(p.isResettable(), false);
1298         QCOMPARE(p.reset(), false);
1299     }
1300
1301     // Automatic signal property
1302     {
1303         PropertyObject o;
1304         QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged");
1305
1306         QCOMPARE(p.isResettable(), false);
1307         QCOMPARE(p.reset(), false);
1308     }
1309 }
1310
1311 void tst_qdeclarativeproperty::writeObjectToList()
1312 {
1313     QDeclarativeComponent containerComponent(&engine);
1314     containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl());
1315     MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create());
1316     QVERIFY(container != 0);
1317     QDeclarativeListReference list(container, "children");
1318     QVERIFY(list.count() == 1);
1319
1320     MyQmlObject *object = new MyQmlObject;
1321     QDeclarativeProperty prop(container, "children");
1322     prop.write(qVariantFromValue(object));
1323     QCOMPARE(list.count(), 1);
1324     QCOMPARE(list.at(0), qobject_cast<QObject*>(object));
1325 }
1326
1327 Q_DECLARE_METATYPE(QList<QObject *>);
1328 void tst_qdeclarativeproperty::writeListToList()
1329 {
1330     QDeclarativeComponent containerComponent(&engine);
1331     containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl());
1332     MyContainer *container = qobject_cast<MyContainer*>(containerComponent.create());
1333     QVERIFY(container != 0);
1334     QDeclarativeListReference list(container, "children");
1335     QVERIFY(list.count() == 1);
1336
1337     QList<QObject*> objList;
1338     objList << new MyQmlObject() << new MyQmlObject() << new MyQmlObject() << new MyQmlObject();
1339     QDeclarativeProperty prop(container, "children");
1340     prop.write(qVariantFromValue(objList));
1341     QCOMPARE(list.count(), 4);
1342
1343     //XXX need to try this with read/write prop (for read-only it correctly doesn't write)
1344     /*QList<MyQmlObject*> typedObjList;
1345     typedObjList << new MyQmlObject();
1346     prop.write(qVariantFromValue(&typedObjList));
1347     QCOMPARE(container->children()->size(), 1);*/
1348 }
1349
1350 void tst_qdeclarativeproperty::crashOnValueProperty()
1351 {
1352     QDeclarativeEngine *engine = new QDeclarativeEngine;
1353     QDeclarativeComponent component(engine);
1354
1355     component.setData("import Test 1.0\nPropertyObject { wrectProperty.x: 10 }", QUrl());
1356     PropertyObject *obj = qobject_cast<PropertyObject*>(component.create());
1357     QVERIFY(obj != 0);
1358
1359     QDeclarativeProperty p(obj, "wrectProperty.x", qmlContext(obj));
1360     QCOMPARE(p.name(), QString("wrectProperty.x"));
1361
1362     QCOMPARE(p.read(), QVariant(10));
1363
1364     //don't crash once the engine is deleted
1365     delete engine;
1366     engine = 0;
1367
1368     QCOMPARE(p.propertyTypeName(), "int");
1369     QCOMPARE(p.read(), QVariant(10));
1370     p.write(QVariant(20));
1371     QCOMPARE(p.read(), QVariant(20));
1372 }
1373
1374 // QTBUG-13719
1375 void tst_qdeclarativeproperty::aliasPropertyBindings()
1376 {
1377     QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyBindings.qml"));
1378
1379     QObject *object = component.create();
1380     QVERIFY(object != 0);
1381
1382     QCOMPARE(object->property("realProperty").toReal(), 90.);
1383     QCOMPARE(object->property("aliasProperty").toReal(), 90.);
1384
1385     object->setProperty("test", 10);
1386
1387     QCOMPARE(object->property("realProperty").toReal(), 110.);
1388     QCOMPARE(object->property("aliasProperty").toReal(), 110.);
1389
1390     QDeclarativeProperty realProperty(object, QLatin1String("realProperty"));
1391     QDeclarativeProperty aliasProperty(object, QLatin1String("aliasProperty"));
1392
1393     // Check there is a binding on these two properties
1394     QVERIFY(QDeclarativePropertyPrivate::binding(realProperty) != 0);
1395     QVERIFY(QDeclarativePropertyPrivate::binding(aliasProperty) != 0);
1396
1397     // Check that its the same binding on these two properties
1398     QCOMPARE(QDeclarativePropertyPrivate::binding(realProperty),
1399              QDeclarativePropertyPrivate::binding(aliasProperty));
1400
1401     // Change the binding
1402     object->setProperty("state", QString("switch"));
1403
1404     QVERIFY(QDeclarativePropertyPrivate::binding(realProperty) != 0);
1405     QVERIFY(QDeclarativePropertyPrivate::binding(aliasProperty) != 0);
1406     QCOMPARE(QDeclarativePropertyPrivate::binding(realProperty),
1407              QDeclarativePropertyPrivate::binding(aliasProperty));
1408
1409     QCOMPARE(object->property("realProperty").toReal(), 96.);
1410     QCOMPARE(object->property("aliasProperty").toReal(), 96.);
1411
1412     // Check the old binding really has not effect any more
1413     object->setProperty("test", 4);
1414
1415     QCOMPARE(object->property("realProperty").toReal(), 96.);
1416     QCOMPARE(object->property("aliasProperty").toReal(), 96.);
1417
1418     object->setProperty("test2", 9);
1419
1420     QCOMPARE(object->property("realProperty").toReal(), 288.);
1421     QCOMPARE(object->property("aliasProperty").toReal(), 288.);
1422
1423     // Revert
1424     object->setProperty("state", QString(""));
1425
1426     QVERIFY(QDeclarativePropertyPrivate::binding(realProperty) != 0);
1427     QVERIFY(QDeclarativePropertyPrivate::binding(aliasProperty) != 0);
1428     QCOMPARE(QDeclarativePropertyPrivate::binding(realProperty),
1429              QDeclarativePropertyPrivate::binding(aliasProperty));
1430
1431     QCOMPARE(object->property("realProperty").toReal(), 20.);
1432     QCOMPARE(object->property("aliasProperty").toReal(), 20.);
1433
1434     object->setProperty("test2", 3);
1435
1436     QCOMPARE(object->property("realProperty").toReal(), 20.);
1437     QCOMPARE(object->property("aliasProperty").toReal(), 20.);
1438
1439     delete object;
1440 }
1441
1442 void tst_qdeclarativeproperty::copy()
1443 {
1444     PropertyObject object;
1445
1446     QDeclarativeProperty *property = new QDeclarativeProperty(&object, QLatin1String("defaultProperty"));
1447     QCOMPARE(property->name(), QString("defaultProperty"));
1448     QCOMPARE(property->read(), QVariant(10));
1449     QCOMPARE(property->type(), QDeclarativeProperty::Property);
1450     QCOMPARE(property->propertyTypeCategory(), QDeclarativeProperty::Normal);
1451     QCOMPARE(property->propertyType(), (int)QVariant::Int);
1452
1453     QDeclarativeProperty p1(*property);
1454     QCOMPARE(p1.name(), QString("defaultProperty"));
1455     QCOMPARE(p1.read(), QVariant(10));
1456     QCOMPARE(p1.type(), QDeclarativeProperty::Property);
1457     QCOMPARE(p1.propertyTypeCategory(), QDeclarativeProperty::Normal);
1458     QCOMPARE(p1.propertyType(), (int)QVariant::Int);
1459
1460     QDeclarativeProperty p2(&object, QLatin1String("url"));
1461     QCOMPARE(p2.name(), QString("url"));
1462     p2 = *property;
1463     QCOMPARE(p2.name(), QString("defaultProperty"));
1464     QCOMPARE(p2.read(), QVariant(10));
1465     QCOMPARE(p2.type(), QDeclarativeProperty::Property);
1466     QCOMPARE(p2.propertyTypeCategory(), QDeclarativeProperty::Normal);
1467     QCOMPARE(p2.propertyType(), (int)QVariant::Int);
1468
1469     delete property; property = 0;
1470
1471     QCOMPARE(p1.name(), QString("defaultProperty"));
1472     QCOMPARE(p1.read(), QVariant(10));
1473     QCOMPARE(p1.type(), QDeclarativeProperty::Property);
1474     QCOMPARE(p1.propertyTypeCategory(), QDeclarativeProperty::Normal);
1475     QCOMPARE(p1.propertyType(), (int)QVariant::Int);
1476
1477     QCOMPARE(p2.name(), QString("defaultProperty"));
1478     QCOMPARE(p2.read(), QVariant(10));
1479     QCOMPARE(p2.type(), QDeclarativeProperty::Property);
1480     QCOMPARE(p2.propertyTypeCategory(), QDeclarativeProperty::Normal);
1481     QCOMPARE(p2.propertyType(), (int)QVariant::Int);
1482 }
1483
1484 void tst_qdeclarativeproperty::initTestCase()
1485 {
1486     qmlRegisterType<MyQmlObject>("Test",1,0,"MyQmlObject");
1487     qmlRegisterType<PropertyObject>("Test",1,0,"PropertyObject");
1488     qmlRegisterType<MyContainer>("Test",1,0,"MyContainer");
1489 }
1490
1491
1492 QTEST_MAIN(tst_qdeclarativeproperty)
1493
1494 #include "tst_qdeclarativeproperty.moc"