Fix QDeclarativeListProperty assignment
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativeecmascript / tst_qdeclarativeecmascript.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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include "testtypes.h"
53 #include "testhttpserver.h"
54 #include "../../../shared/util.h"
55
56 #ifdef Q_OS_SYMBIAN
57 // In Symbian OS test data is located in applications private dir
58 #define SRCDIR "."
59 #endif
60
61 /*
62 This test covers evaluation of ECMAScript expressions and bindings from within
63 QML.  This does not include static QML language issues.
64
65 Static QML language issues are covered in qmllanguage
66 */
67 inline QUrl TEST_FILE(const QString &filename)
68 {
69     QFileInfo fileInfo(__FILE__);
70     return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
71 }
72
73 inline QUrl TEST_FILE(const char *filename)
74 {
75     return TEST_FILE(QLatin1String(filename));
76 }
77
78 class tst_qdeclarativeecmascript : public QObject
79 {
80     Q_OBJECT
81 public:
82     tst_qdeclarativeecmascript() {}
83
84 private slots:
85     void initTestCase();
86     void assignBasicTypes();
87     void idShortcutInvalidates();
88     void boolPropertiesEvaluateAsBool();
89     void methods();
90     void signalAssignment();
91     void bindingLoop();
92     void basicExpressions();
93     void basicExpressions_data();
94     void arrayExpressions();
95     void contextPropertiesTriggerReeval();
96     void objectPropertiesTriggerReeval();
97     void deferredProperties();
98     void deferredPropertiesErrors();
99     void extensionObjects();
100     void overrideExtensionProperties();
101     void attachedProperties();
102     void enums();
103     void valueTypeFunctions();
104     void constantsOverrideBindings();
105     void outerBindingOverridesInnerBinding();
106     void aliasPropertyAndBinding();
107     void aliasPropertyReset();
108     void nonExistentAttachedObject();
109     void scope();
110     void importScope();
111     void signalParameterTypes();
112     void objectsCompareAsEqual();
113     void dynamicCreation_data();
114     void dynamicCreation();
115     void dynamicDestruction();
116     void objectToString();
117     void objectHasOwnProperty();
118     void selfDeletingBinding();
119     void extendedObjectPropertyLookup();
120     void scriptErrors();
121     void functionErrors();
122     void propertyAssignmentErrors();
123     void signalTriggeredBindings();
124     void listProperties();
125     void exceptionClearsOnReeval();
126     void exceptionSlotProducesWarning();
127     void exceptionBindingProducesWarning();
128     void transientErrors();
129     void shutdownErrors();
130     void compositePropertyType();
131     void jsObject();
132     void undefinedResetsProperty();
133     void listToVariant();
134     void listAssignment();
135     void multiEngineObject();
136     void deletedObject();
137     void attachedPropertyScope();
138     void scriptConnect();
139     void scriptDisconnect();
140     void ownership();
141     void cppOwnershipReturnValue();
142     void ownershipCustomReturnValue();
143     void qlistqobjectMethods();
144     void strictlyEquals();
145     void compiled();
146     void numberAssignment();
147     void propertySplicing();
148     void signalWithUnknownTypes();
149     void moduleApi_data();
150     void moduleApi();
151     void importScripts();
152     void scarceResources();
153     void propertyChangeSlots();
154     void elementAssign();
155     void objectPassThroughSignals();
156     void booleanConversion();
157     void handleReferenceManagement();
158
159     void bug1();
160     void bug2();
161     void dynamicCreationCrash();
162     void regExpBug();
163     void nullObjectBinding();
164     void deletedEngine();
165     void libraryScriptAssert();
166     void variantsAssignedUndefined();
167     void qtbug_9792();
168     void qtcreatorbug_1289();
169     void noSpuriousWarningsAtShutdown();
170     void canAssignNullToQObject();
171     void functionAssignment_fromBinding();
172     void functionAssignment_fromJS();
173     void functionAssignment_fromJS_data();
174     void functionAssignmentfromJS_invalid();
175     void eval();
176     void function();
177     void qtbug_10696();
178     void qtbug_11606();
179     void qtbug_11600();
180     void nonscriptable();
181     void deleteLater();
182     void in();
183     void sharedAttachedObject();
184     void objectName();
185     void writeRemovesBinding();
186     void aliasBindingsAssignCorrectly();
187     void aliasBindingsOverrideTarget();
188     void aliasWritesOverrideBindings();
189     void aliasToCompositeElement();
190     void realToInt();
191     void dynamicString();
192     void include();
193     void signalHandlers();
194
195     void callQtInvokables();
196     void invokableObjectArg();
197     void invokableObjectRet();
198
199     void revisionErrors();
200     void revision();
201
202 private:
203     QDeclarativeEngine engine;
204 };
205
206 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
207
208 void tst_qdeclarativeecmascript::assignBasicTypes()
209 {
210     {
211     QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
212     MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
213     QVERIFY(object != 0);
214     QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
215     QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
216     QCOMPARE(object->stringProperty(), QString("Hello World!"));
217     QCOMPARE(object->uintProperty(), uint(10));
218     QCOMPARE(object->intProperty(), -19);
219     QCOMPARE((float)object->realProperty(), float(23.2));
220     QCOMPARE((float)object->doubleProperty(), float(-19.75));
221     QCOMPARE((float)object->floatProperty(), float(8.5));
222     QCOMPARE(object->colorProperty(), QColor("red"));
223     QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
224     QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
225     QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
226     QCOMPARE(object->pointProperty(), QPoint(99,13));
227     QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
228     QCOMPARE(object->sizeProperty(), QSize(99, 13));
229     QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
230     QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
231     QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
232     QCOMPARE(object->boolProperty(), true);
233     QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
234     QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
235     QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
236     delete object;
237     }
238     {
239     QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
240     MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
241     QVERIFY(object != 0);
242     QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
243     QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
244     QCOMPARE(object->stringProperty(), QString("Hello World!"));
245     QCOMPARE(object->uintProperty(), uint(10));
246     QCOMPARE(object->intProperty(), -19);
247     QCOMPARE((float)object->realProperty(), float(23.2));
248     QCOMPARE((float)object->doubleProperty(), float(-19.75));
249     QCOMPARE((float)object->floatProperty(), float(8.5));
250     QCOMPARE(object->colorProperty(), QColor("red"));
251     QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
252     QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
253     QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
254     QCOMPARE(object->pointProperty(), QPoint(99,13));
255     QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
256     QCOMPARE(object->sizeProperty(), QSize(99, 13));
257     QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
258     QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
259     QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
260     QCOMPARE(object->boolProperty(), true);
261     QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
262     QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
263     QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
264     delete object;
265     }
266 }
267
268 void tst_qdeclarativeecmascript::idShortcutInvalidates()
269 {
270     {
271         QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
272         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
273         QVERIFY(object != 0);
274         QVERIFY(object->objectProperty() != 0);
275         delete object->objectProperty();
276         QVERIFY(object->objectProperty() == 0);
277         delete object;
278     }
279
280     {
281         QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
282         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
283         QVERIFY(object != 0);
284         QVERIFY(object->objectProperty() != 0);
285         delete object->objectProperty();
286         QVERIFY(object->objectProperty() == 0);
287         delete object;
288     }
289 }
290
291 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
292 {
293     {
294         QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
295         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
296         QVERIFY(object != 0);
297         QCOMPARE(object->stringProperty(), QLatin1String("pass"));
298         delete object;
299     }
300     {
301         QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
302         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
303         QVERIFY(object != 0);
304         QCOMPARE(object->stringProperty(), QLatin1String("pass"));
305         delete object;
306     }
307 }
308
309 void tst_qdeclarativeecmascript::signalAssignment()
310 {
311     {
312         QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
313         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
314         QVERIFY(object != 0);
315         QCOMPARE(object->string(), QString());
316         emit object->basicSignal();
317         QCOMPARE(object->string(), QString("pass"));
318         delete object;
319     }
320
321     {
322         QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
323         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
324         QVERIFY(object != 0);
325         QCOMPARE(object->string(), QString());
326         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
327         QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
328         delete object;
329     }
330 }
331
332 void tst_qdeclarativeecmascript::methods()
333 {
334     {
335         QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
336         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
337         QVERIFY(object != 0);
338         QCOMPARE(object->methodCalled(), false);
339         QCOMPARE(object->methodIntCalled(), false);
340         emit object->basicSignal();
341         QCOMPARE(object->methodCalled(), true);
342         QCOMPARE(object->methodIntCalled(), false);
343         delete object;
344     }
345
346     {
347         QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
348         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
349         QVERIFY(object != 0);
350         QCOMPARE(object->methodCalled(), false);
351         QCOMPARE(object->methodIntCalled(), false);
352         emit object->basicSignal();
353         QCOMPARE(object->methodCalled(), false);
354         QCOMPARE(object->methodIntCalled(), true);
355         delete object;
356     }
357
358     {
359         QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
360         QObject *object = component.create();
361         QVERIFY(object != 0);
362         QCOMPARE(object->property("test").toInt(), 19);
363         delete object;
364     }
365
366     {
367         QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
368         QObject *object = component.create();
369         QVERIFY(object != 0);
370         QCOMPARE(object->property("test").toInt(), 19);
371         QCOMPARE(object->property("test2").toInt(), 17);
372         QCOMPARE(object->property("test3").toInt(), 16);
373         delete object;
374     }
375
376     {
377         QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
378         QObject *object = component.create();
379         QVERIFY(object != 0);
380         QCOMPARE(object->property("test").toInt(), 9);
381         delete object;
382     }
383 }
384
385 void tst_qdeclarativeecmascript::bindingLoop()
386 {
387     QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
388     QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
389     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
390     QObject *object = component.create();
391     QVERIFY(object != 0);
392     delete object;
393 }
394
395 void tst_qdeclarativeecmascript::basicExpressions_data()
396 {
397     QTest::addColumn<QString>("expression");
398     QTest::addColumn<QVariant>("result");
399     QTest::addColumn<bool>("nest");
400
401     QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
402     QTest::newRow("Context property") << "a" << QVariant(1944) << false;
403     QTest::newRow("Context property") << "a" << QVariant(1944) << true;
404     QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
405     QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
406     QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
407     QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
408     QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
409     QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
410     QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
411     QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
412     QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
413     QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
414     QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
415     QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
416     QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
417     QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
418     QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
419     QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
420 }
421
422 void tst_qdeclarativeecmascript::basicExpressions()
423 {
424     QFETCH(QString, expression);
425     QFETCH(QVariant, result);
426     QFETCH(bool, nest);
427
428     MyQmlObject object1;
429     MyQmlObject object2;
430     MyQmlObject object3;
431     MyDefaultObject1 default1;
432     MyDefaultObject3 default3;
433     object1.setStringProperty("Object1");
434     object2.setStringProperty("Object2");
435     object3.setStringProperty("Object3");
436
437     QDeclarativeContext context(engine.rootContext());
438     QDeclarativeContext nestedContext(&context);
439
440     context.setContextObject(&default1);
441     context.setContextProperty("a", QVariant(1944));
442     context.setContextProperty("b", QVariant("Milk"));
443     context.setContextProperty("object", &object1);
444     context.setContextProperty("objectOverride", &object2);
445     nestedContext.setContextObject(&default3);
446     nestedContext.setContextProperty("b", QVariant("Cow"));
447     nestedContext.setContextProperty("objectOverride", &object3);
448     nestedContext.setContextProperty("millipedeLegs", QVariant(100));
449
450     MyExpression expr(nest?&nestedContext:&context, expression);
451     QCOMPARE(expr.evaluate(), result);
452 }
453
454 void tst_qdeclarativeecmascript::arrayExpressions()
455 {
456     QObject obj1;
457     QObject obj2;
458     QObject obj3;
459
460     QDeclarativeContext context(engine.rootContext());
461     context.setContextProperty("a", &obj1);
462     context.setContextProperty("b", &obj2);
463     context.setContextProperty("c", &obj3);
464
465     MyExpression expr(&context, "[a, b, c, 10]");
466     QVariant result = expr.evaluate();
467     QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
468     QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
469     QCOMPARE(list.count(), 4);
470     QCOMPARE(list.at(0), &obj1);
471     QCOMPARE(list.at(1), &obj2);
472     QCOMPARE(list.at(2), &obj3);
473     QCOMPARE(list.at(3), (QObject *)0);
474 }
475
476 // Tests that modifying a context property will reevaluate expressions
477 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
478 {
479     QDeclarativeContext context(engine.rootContext());
480     MyQmlObject object1;
481     MyQmlObject object2;
482     MyQmlObject *object3 = new MyQmlObject;
483
484     object1.setStringProperty("Hello");
485     object2.setStringProperty("World");
486
487     context.setContextProperty("testProp", QVariant(1));
488     context.setContextProperty("testObj", &object1);
489     context.setContextProperty("testObj2", object3);
490
491     { 
492         MyExpression expr(&context, "testProp + 1");
493         QCOMPARE(expr.changed, false);
494         QCOMPARE(expr.evaluate(), QVariant(2));
495
496         context.setContextProperty("testProp", QVariant(2));
497         QCOMPARE(expr.changed, true);
498         QCOMPARE(expr.evaluate(), QVariant(3));
499     }
500
501     { 
502         MyExpression expr(&context, "testProp + testProp + testProp");
503         QCOMPARE(expr.changed, false);
504         QCOMPARE(expr.evaluate(), QVariant(6));
505
506         context.setContextProperty("testProp", QVariant(4));
507         QCOMPARE(expr.changed, true);
508         QCOMPARE(expr.evaluate(), QVariant(12));
509     }
510
511     { 
512         MyExpression expr(&context, "testObj.stringProperty");
513         QCOMPARE(expr.changed, false);
514         QCOMPARE(expr.evaluate(), QVariant("Hello"));
515
516         context.setContextProperty("testObj", &object2);
517         QCOMPARE(expr.changed, true);
518         QCOMPARE(expr.evaluate(), QVariant("World"));
519     }
520
521     { 
522         MyExpression expr(&context, "testObj.stringProperty /**/");
523         QCOMPARE(expr.changed, false);
524         QCOMPARE(expr.evaluate(), QVariant("World"));
525
526         context.setContextProperty("testObj", &object1);
527         QCOMPARE(expr.changed, true);
528         QCOMPARE(expr.evaluate(), QVariant("Hello"));
529     }
530
531     { 
532         MyExpression expr(&context, "testObj2");
533         QCOMPARE(expr.changed, false);
534         QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
535     }
536
537     delete object3;
538 }
539
540 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
541 {
542     QDeclarativeContext context(engine.rootContext());
543     MyQmlObject object1;
544     MyQmlObject object2;
545     MyQmlObject object3;
546     context.setContextProperty("testObj", &object1);
547
548     object1.setStringProperty(QLatin1String("Hello"));
549     object2.setStringProperty(QLatin1String("Dog"));
550     object3.setStringProperty(QLatin1String("Cat"));
551
552     { 
553         MyExpression expr(&context, "testObj.stringProperty");
554         QCOMPARE(expr.changed, false);
555         QCOMPARE(expr.evaluate(), QVariant("Hello"));
556
557         object1.setStringProperty(QLatin1String("World"));
558         QCOMPARE(expr.changed, true);
559         QCOMPARE(expr.evaluate(), QVariant("World"));
560     }
561
562     { 
563         MyExpression expr(&context, "testObj.objectProperty.stringProperty");
564         QCOMPARE(expr.changed, false);
565         QCOMPARE(expr.evaluate(), QVariant());
566
567         object1.setObjectProperty(&object2);
568         QCOMPARE(expr.changed, true);
569         expr.changed = false;
570         QCOMPARE(expr.evaluate(), QVariant("Dog"));
571
572         object1.setObjectProperty(&object3);
573         QCOMPARE(expr.changed, true);
574         expr.changed = false;
575         QCOMPARE(expr.evaluate(), QVariant("Cat"));
576
577         object1.setObjectProperty(0);
578         QCOMPARE(expr.changed, true);
579         expr.changed = false;
580         QCOMPARE(expr.evaluate(), QVariant());
581
582         object1.setObjectProperty(&object3);
583         QCOMPARE(expr.changed, true);
584         expr.changed = false;
585         QCOMPARE(expr.evaluate(), QVariant("Cat"));
586
587         object3.setStringProperty("Donkey");
588         QCOMPARE(expr.changed, true);
589         expr.changed = false;
590         QCOMPARE(expr.evaluate(), QVariant("Donkey"));
591     }
592 }
593
594 void tst_qdeclarativeecmascript::deferredProperties()
595 {
596     QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
597     MyDeferredObject *object = 
598         qobject_cast<MyDeferredObject *>(component.create());
599     QVERIFY(object != 0);
600     QCOMPARE(object->value(), 0);
601     QVERIFY(object->objectProperty() == 0);
602     QVERIFY(object->objectProperty2() != 0);
603     qmlExecuteDeferred(object);
604     QCOMPARE(object->value(), 10);
605     QVERIFY(object->objectProperty() != 0);
606     MyQmlObject *qmlObject = 
607         qobject_cast<MyQmlObject *>(object->objectProperty());
608     QVERIFY(qmlObject != 0);
609     QCOMPARE(qmlObject->value(), 10);
610     object->setValue(19);
611     QCOMPARE(qmlObject->value(), 19);
612
613     delete object;
614 }
615
616 // Check errors on deferred properties are correctly emitted
617 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
618 {
619     QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
620     MyDeferredObject *object = 
621         qobject_cast<MyDeferredObject *>(component.create());
622     QVERIFY(object != 0);
623     QCOMPARE(object->value(), 0);
624     QVERIFY(object->objectProperty() == 0);
625     QVERIFY(object->objectProperty2() == 0);
626
627     QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
628     QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
629
630     qmlExecuteDeferred(object);
631
632     delete object;
633 }
634
635 void tst_qdeclarativeecmascript::extensionObjects()
636 {
637     QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
638     MyExtendedObject *object = 
639         qobject_cast<MyExtendedObject *>(component.create());
640     QVERIFY(object != 0);
641     QCOMPARE(object->baseProperty(), 13);
642     QCOMPARE(object->coreProperty(), 9);
643     object->setProperty("extendedProperty", QVariant(11));
644     object->setProperty("baseExtendedProperty", QVariant(92));
645     QCOMPARE(object->coreProperty(), 11);
646     QCOMPARE(object->baseProperty(), 92);
647
648     MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
649     QVERIFY(nested);
650     QCOMPARE(nested->baseProperty(), 13);
651     QCOMPARE(nested->coreProperty(), 9);
652     nested->setProperty("extendedProperty", QVariant(11));
653     nested->setProperty("baseExtendedProperty", QVariant(92));
654     QCOMPARE(nested->coreProperty(), 11);
655     QCOMPARE(nested->baseProperty(), 92);
656
657     delete object;
658 }
659
660 void tst_qdeclarativeecmascript::overrideExtensionProperties()
661 {
662     QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
663     OverrideDefaultPropertyObject *object =
664         qobject_cast<OverrideDefaultPropertyObject *>(component.create());
665     QVERIFY(object != 0);
666     QVERIFY(object->secondProperty() != 0);
667     QVERIFY(object->firstProperty() == 0);
668
669     delete object;
670 }
671
672 void tst_qdeclarativeecmascript::attachedProperties()
673 {
674     {
675         QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
676         QObject *object = component.create();
677         QVERIFY(object != 0);
678         QCOMPARE(object->property("a").toInt(), 19);
679         QCOMPARE(object->property("b").toInt(), 19);
680         QCOMPARE(object->property("c").toInt(), 19);
681         QCOMPARE(object->property("d").toInt(), 19);
682         delete object;
683     }
684
685     {
686         QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
687         QObject *object = component.create();
688         QVERIFY(object != 0);
689         QCOMPARE(object->property("a").toInt(), 26);
690         QCOMPARE(object->property("b").toInt(), 26);
691         QCOMPARE(object->property("c").toInt(), 26);
692         QCOMPARE(object->property("d").toInt(), 26);
693
694         delete object;
695     }
696
697     {
698         QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
699         QObject *object = component.create();
700         QVERIFY(object != 0);
701
702         QMetaObject::invokeMethod(object, "writeValue2");
703
704         MyQmlAttachedObject *attached =
705             qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
706         QVERIFY(attached != 0);
707
708         QCOMPARE(attached->value2(), 9);
709         delete object;
710     }
711 }
712
713 void tst_qdeclarativeecmascript::enums()
714 {
715     // Existent enums
716     {
717     QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
718     QObject *object = component.create();
719     QVERIFY(object != 0);
720
721     QCOMPARE(object->property("a").toInt(), 0);
722     QCOMPARE(object->property("b").toInt(), 1);
723     QCOMPARE(object->property("c").toInt(), 2);
724     QCOMPARE(object->property("d").toInt(), 3);
725     QCOMPARE(object->property("e").toInt(), 0);
726     QCOMPARE(object->property("f").toInt(), 1);
727     QCOMPARE(object->property("g").toInt(), 2);
728     QCOMPARE(object->property("h").toInt(), 3);
729     QCOMPARE(object->property("i").toInt(), 19);
730     QCOMPARE(object->property("j").toInt(), 19);
731
732     delete object;
733     }
734     // Non-existent enums
735     {
736     QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
737
738     QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
739     QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
740     QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
741     QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
742
743     QObject *object = component.create();
744     QVERIFY(object != 0);
745     QCOMPARE(object->property("a").toInt(), 0);
746     QCOMPARE(object->property("b").toInt(), 0);
747
748     delete object;
749     }
750 }
751
752 void tst_qdeclarativeecmascript::valueTypeFunctions()
753 {
754     QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
755     MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
756     QVERIFY(obj != 0);
757     QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
758     QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
759
760     delete obj;
761 }
762
763 /* 
764 Tests that writing a constant to a property with a binding on it disables the
765 binding.
766 */
767 void tst_qdeclarativeecmascript::constantsOverrideBindings()
768 {
769     // From ECMAScript
770     {
771         QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
772         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
773         QVERIFY(object != 0);
774
775         QCOMPARE(object->property("c2").toInt(), 0);
776         object->setProperty("c1", QVariant(9));
777         QCOMPARE(object->property("c2").toInt(), 9);
778
779         emit object->basicSignal();
780
781         QCOMPARE(object->property("c2").toInt(), 13);
782         object->setProperty("c1", QVariant(8));
783         QCOMPARE(object->property("c2").toInt(), 13);
784
785         delete object;
786     }
787
788     // During construction
789     {
790         QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
791         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
792         QVERIFY(object != 0);
793
794         QCOMPARE(object->property("c1").toInt(), 0);
795         QCOMPARE(object->property("c2").toInt(), 10);
796         object->setProperty("c1", QVariant(9));
797         QCOMPARE(object->property("c1").toInt(), 9);
798         QCOMPARE(object->property("c2").toInt(), 10);
799
800         delete object;
801     }
802
803 #if 0
804     // From C++
805     {
806         QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
807         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
808         QVERIFY(object != 0);
809
810         QCOMPARE(object->property("c2").toInt(), 0);
811         object->setProperty("c1", QVariant(9));
812         QCOMPARE(object->property("c2").toInt(), 9);
813
814         object->setProperty("c2", QVariant(13));
815         QCOMPARE(object->property("c2").toInt(), 13);
816         object->setProperty("c1", QVariant(7));
817         QCOMPARE(object->property("c1").toInt(), 7);
818         QCOMPARE(object->property("c2").toInt(), 13);
819
820         delete object;
821     }
822 #endif
823
824     // Using an alias
825     {
826         QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
827         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
828         QVERIFY(object != 0);
829
830         QCOMPARE(object->property("c1").toInt(), 0);
831         QCOMPARE(object->property("c3").toInt(), 10);
832         object->setProperty("c1", QVariant(9));
833         QCOMPARE(object->property("c1").toInt(), 9);
834         QCOMPARE(object->property("c3").toInt(), 10);
835
836         delete object;
837     }
838 }
839
840 /*
841 Tests that assigning a binding to a property that already has a binding causes
842 the original binding to be disabled.
843 */
844 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
845 {
846     QDeclarativeComponent component(&engine, 
847                            TEST_FILE("outerBindingOverridesInnerBinding.qml"));
848     MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
849     QVERIFY(object != 0);
850
851     QCOMPARE(object->property("c1").toInt(), 0);
852     QCOMPARE(object->property("c2").toInt(), 0);
853     QCOMPARE(object->property("c3").toInt(), 0);
854
855     object->setProperty("c1", QVariant(9));
856     QCOMPARE(object->property("c1").toInt(), 9);
857     QCOMPARE(object->property("c2").toInt(), 0);
858     QCOMPARE(object->property("c3").toInt(), 0);
859
860     object->setProperty("c3", QVariant(8));
861     QCOMPARE(object->property("c1").toInt(), 9);
862     QCOMPARE(object->property("c2").toInt(), 8);
863     QCOMPARE(object->property("c3").toInt(), 8);
864
865     delete object;
866 }
867
868 /*
869 Access a non-existent attached object.  
870
871 Tests for a regression where this used to crash.
872 */
873 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
874 {
875     QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
876
877     QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
878     QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
879
880     QObject *object = component.create();
881     QVERIFY(object != 0);
882
883     delete object;
884 }
885
886 void tst_qdeclarativeecmascript::scope()
887 {
888     {
889         QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
890         QObject *object = component.create();
891         QVERIFY(object != 0);
892
893         QCOMPARE(object->property("test1").toInt(), 1);
894         QCOMPARE(object->property("test2").toInt(), 2);
895         QCOMPARE(object->property("test3").toString(), QString("1Test"));
896         QCOMPARE(object->property("test4").toString(), QString("2Test"));
897         QCOMPARE(object->property("test5").toInt(), 1);
898         QCOMPARE(object->property("test6").toInt(), 1);
899         QCOMPARE(object->property("test7").toInt(), 2);
900         QCOMPARE(object->property("test8").toInt(), 2);
901         QCOMPARE(object->property("test9").toInt(), 1);
902         QCOMPARE(object->property("test10").toInt(), 3);
903
904         delete object;
905     }
906
907     {
908         QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
909         QObject *object = component.create();
910         QVERIFY(object != 0);
911
912         QCOMPARE(object->property("test1").toInt(), 19);
913         QCOMPARE(object->property("test2").toInt(), 19);
914         QCOMPARE(object->property("test3").toInt(), 14);
915         QCOMPARE(object->property("test4").toInt(), 14);
916         QCOMPARE(object->property("test5").toInt(), 24);
917         QCOMPARE(object->property("test6").toInt(), 24);
918
919         delete object;
920     }
921
922     {
923         QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
924         QObject *object = component.create();
925         QVERIFY(object != 0);
926
927         QCOMPARE(object->property("test1").toBool(), true);
928         QCOMPARE(object->property("test2").toBool(), true);
929         QCOMPARE(object->property("test3").toBool(), true);
930
931         delete object;
932     }
933
934     // Signal argument scope
935     {
936         QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
937         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
938         QVERIFY(object != 0);
939
940         QCOMPARE(object->property("test").toInt(), 0);
941         QCOMPARE(object->property("test2").toString(), QString());
942
943         emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
944
945         QCOMPARE(object->property("test").toInt(), 13);
946         QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
947
948         delete object;
949     }
950
951     {
952         QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
953         QObject *object = component.create();
954         QVERIFY(object != 0);
955
956         QCOMPARE(object->property("test1").toBool(), true);
957         QCOMPARE(object->property("test2").toBool(), true);
958
959         delete object;
960     }
961
962     {
963         QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
964         QObject *object = component.create();
965         QVERIFY(object != 0);
966
967         QCOMPARE(object->property("test").toBool(), true);
968
969         delete object;
970     }
971 }
972
973 // In 4.7, non-library javascript files that had no imports shared the imports of their
974 // importing context
975 void tst_qdeclarativeecmascript::importScope()
976 {
977     QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
978     QObject *o = component.create();
979     QVERIFY(o != 0);
980
981     QCOMPARE(o->property("test").toInt(), 240);
982
983     delete o;
984 }
985
986 /*
987 Tests that "any" type passes through a synthesized signal parameter.  This
988 is essentially a test of QDeclarativeMetaType::copy()
989 */
990 void tst_qdeclarativeecmascript::signalParameterTypes()
991 {
992     QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
993     MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
994     QVERIFY(object != 0);
995
996     emit object->basicSignal();
997
998     QCOMPARE(object->property("intProperty").toInt(), 10);
999     QCOMPARE(object->property("realProperty").toReal(), 19.2);
1000     QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1001     QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1002     QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1003     QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1004
1005     delete object;
1006 }
1007
1008 /*
1009 Test that two JS objects for the same QObject compare as equal.
1010 */
1011 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1012 {
1013     QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1014     QObject *object = component.create();
1015     QVERIFY(object != 0);
1016
1017     QCOMPARE(object->property("test1").toBool(), true);
1018     QCOMPARE(object->property("test2").toBool(), true);
1019     QCOMPARE(object->property("test3").toBool(), true);
1020     QCOMPARE(object->property("test4").toBool(), true);
1021     QCOMPARE(object->property("test5").toBool(), true);
1022
1023     delete object;
1024 }
1025
1026 /*
1027 Confirm bindings and alias properties can coexist.
1028
1029 Tests for a regression where the binding would not reevaluate.
1030 */
1031 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1032 {
1033     QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1034     QObject *object = component.create();
1035     QVERIFY(object != 0);
1036
1037     QCOMPARE(object->property("c2").toInt(), 3);
1038     QCOMPARE(object->property("c3").toInt(), 3);
1039
1040     object->setProperty("c2", QVariant(19));
1041
1042     QCOMPARE(object->property("c2").toInt(), 19);
1043     QCOMPARE(object->property("c3").toInt(), 19);
1044
1045     delete object;
1046 }
1047
1048 /*
1049 Ensure that we can write undefined value to an alias property,
1050 and that the aliased property is reset correctly if possible.
1051 */
1052 void tst_qdeclarativeecmascript::aliasPropertyReset()
1053 {
1054     QObject *object = 0;
1055
1056     // test that a manual write (of undefined) to a resettable aliased property succeeds
1057     QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1058     object = c1.create();
1059     QVERIFY(object != 0);
1060     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1061     QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1062     QMetaObject::invokeMethod(object, "resetAliased");
1063     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1064     QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1065     delete object;
1066
1067     // test that a manual write (of undefined) to a resettable alias property succeeds
1068     QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1069     object = c2.create();
1070     QVERIFY(object != 0);
1071     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1072     QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1073     QMetaObject::invokeMethod(object, "resetAlias");
1074     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1075     QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1076     delete object;
1077
1078     // test that an alias to a bound property works correctly
1079     QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1080     object = c3.create();
1081     QVERIFY(object != 0);
1082     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1083     QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1084     QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1085     QMetaObject::invokeMethod(object, "resetAlias");
1086     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1087     QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1088     QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1089     delete object;
1090
1091     // test that a manual write (of undefined) to a resettable alias property
1092     // whose aliased property's object has been deleted, does not crash.
1093     QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1094     object = c4.create();
1095     QVERIFY(object != 0);
1096     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1097     QObject *loader = object->findChild<QObject*>("loader");
1098     QVERIFY(loader != 0);
1099     delete loader;
1100     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1101     QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1102     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1103     QMetaObject::invokeMethod(object, "setAlias");   // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1104     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1105     delete object;
1106
1107     // test that binding an alias property to an undefined value works correctly
1108     QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1109     object = c5.create();
1110     QVERIFY(object != 0);
1111     QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1112     delete object;
1113
1114     // test that a manual write (of undefined) to a non-resettable property fails properly
1115     QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1116     QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1117     QDeclarativeComponent e1(&engine, url);
1118     object = e1.create();
1119     QVERIFY(object != 0);
1120     QCOMPARE(object->property("intAlias").value<int>(), 12);
1121     QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1122     QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1123     QMetaObject::invokeMethod(object, "resetAlias");
1124     QCOMPARE(object->property("intAlias").value<int>(), 12);
1125     QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1126     delete object;
1127 }
1128
1129 void tst_qdeclarativeecmascript::dynamicCreation_data()
1130 {
1131     QTest::addColumn<QString>("method");
1132     QTest::addColumn<QString>("createdName");
1133
1134     QTest::newRow("One") << "createOne" << "objectOne";
1135     QTest::newRow("Two") << "createTwo" << "objectTwo";
1136     QTest::newRow("Three") << "createThree" << "objectThree";
1137 }
1138
1139 /*
1140 Test using createQmlObject to dynamically generate an item
1141 Also using createComponent is tested.
1142 */
1143 void tst_qdeclarativeecmascript::dynamicCreation()
1144 {
1145     QFETCH(QString, method);
1146     QFETCH(QString, createdName);
1147
1148     QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1149     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1150     QVERIFY(object != 0);
1151
1152     QMetaObject::invokeMethod(object, method.toUtf8());
1153     QObject *created = object->objectProperty();
1154     QVERIFY(created);
1155     QCOMPARE(created->objectName(), createdName);
1156
1157     delete object;
1158 }
1159
1160 /*
1161    Tests the destroy function
1162 */
1163 void tst_qdeclarativeecmascript::dynamicDestruction()
1164 {
1165     {
1166     QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1167     QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1168     QVERIFY(object != 0);
1169     QDeclarativeGuard<QObject> createdQmlObject = 0;
1170
1171     QMetaObject::invokeMethod(object, "create");
1172     createdQmlObject = object->objectProperty();
1173     QVERIFY(createdQmlObject);
1174     QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1175
1176     QMetaObject::invokeMethod(object, "killOther");
1177     QVERIFY(createdQmlObject);
1178     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1179     QVERIFY(createdQmlObject);
1180     for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1181         if (createdQmlObject) {
1182             QTest::qWait(100);
1183             QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1184         }
1185     }
1186     QVERIFY(!createdQmlObject);
1187
1188     QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1189     QMetaObject::invokeMethod(object, "killMe");
1190     QVERIFY(object);
1191     QTest::qWait(0);
1192     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1193     QVERIFY(!object);
1194     }
1195
1196     {
1197     QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1198     QObject *o = component.create();
1199     QVERIFY(o != 0);
1200
1201     QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1202
1203     QMetaObject::invokeMethod(o, "create");
1204
1205     QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1206
1207     QMetaObject::invokeMethod(o, "destroy");
1208
1209     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1210
1211     QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1212
1213     delete o;
1214     }
1215 }
1216
1217 /*
1218    tests that id.toString() works
1219 */
1220 void tst_qdeclarativeecmascript::objectToString()
1221 {
1222     QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1223     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1224     QVERIFY(object != 0);
1225     QMetaObject::invokeMethod(object, "testToString");
1226     QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1227     QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1228
1229     delete object;
1230 }
1231
1232 /*
1233   tests that id.hasOwnProperty() works
1234 */
1235 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1236 {
1237     QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1238     QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1239     QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1240     QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1241
1242     QDeclarativeComponent component(&engine, url);
1243     QObject *object = component.create();
1244     QVERIFY(object != 0);
1245
1246     // test QObjects in QML
1247     QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1248     QVERIFY(object->property("result").value<bool>() == true);
1249     QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1250     QVERIFY(object->property("result").value<bool>() == false);
1251
1252     // now test other types in QML
1253     QObject *child = object->findChild<QObject*>("typeObj");
1254     QVERIFY(child != 0);
1255     QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1256     QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1257     QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1258     QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1259     QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1260     QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1261     QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1262     QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1263     QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1264     QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1265     QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1266     QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1267
1268     QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1269     QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1270     QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1271     QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1272     QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1273     QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1274     QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1275     QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1276     QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1277
1278     delete object;
1279 }
1280
1281 /*
1282 Tests bindings that indirectly cause their own deletion work.
1283
1284 This test is best run under valgrind to ensure no invalid memory access occur.
1285 */
1286 void tst_qdeclarativeecmascript::selfDeletingBinding()
1287 {
1288     {
1289         QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1290         QObject *object = component.create();
1291         QVERIFY(object != 0);
1292         object->setProperty("triggerDelete", true);
1293         delete object;
1294     }
1295
1296     {
1297         QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1298         QObject *object = component.create();
1299         QVERIFY(object != 0);
1300         object->setProperty("triggerDelete", true);
1301         delete object;
1302     }
1303 }
1304
1305 /*
1306 Test that extended object properties can be accessed.
1307
1308 This test a regression where this used to crash.  The issue was specificially
1309 for extended objects that did not include a synthesized meta object (so non-root
1310 and no synthesiszed properties).
1311 */
1312 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1313 {
1314     QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1315     QObject *object = component.create();
1316     QVERIFY(object != 0);
1317     delete object;
1318 }
1319
1320 /*
1321 Test file/lineNumbers for binding/Script errors.
1322 */
1323 void tst_qdeclarativeecmascript::scriptErrors()
1324 {
1325     QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1326     QString url = component.url().toString();
1327
1328     QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1329     QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1330     QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1331     QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1332     QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1333     QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1334     QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1335     QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1336
1337     QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1338     QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1339     QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1340     QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1341     QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1342     MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1343     QVERIFY(object != 0);
1344
1345     QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1346     emit object->basicSignal();
1347
1348     QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1349     emit object->anotherBasicSignal();
1350
1351     QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1352     emit object->thirdBasicSignal();
1353
1354     delete object;
1355 }
1356
1357 /*
1358 Test file/lineNumbers for inline functions.
1359 */
1360 void tst_qdeclarativeecmascript::functionErrors()
1361 {
1362     QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1363     QString url = component.url().toString();
1364
1365     QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1366
1367     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1368
1369     QObject *object = component.create();
1370     QVERIFY(object != 0);
1371     delete object;
1372
1373     // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1374     QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1375     url = componentTwo.url().toString();
1376     object = componentTwo.create();
1377     QVERIFY(object != 0);
1378
1379     QString srpname = object->property("srp_name").toString();
1380     
1381     warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname + 
1382               QLatin1String(" is not a function");
1383     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1384     QMetaObject::invokeMethod(object, "retrieveScarceResource");
1385     delete object;
1386 }
1387
1388 /*
1389 Test various errors that can occur when assigning a property from script
1390 */
1391 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1392 {
1393     QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1394
1395     QString url = component.url().toString();
1396
1397     QObject *object = component.create();
1398     QVERIFY(object != 0);
1399
1400     QCOMPARE(object->property("test1").toBool(), true);
1401     QCOMPARE(object->property("test2").toBool(), true);
1402
1403     delete object;
1404 }
1405     
1406 /*
1407 Test bindings still work when the reeval is triggered from within
1408 a signal script.
1409 */
1410 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1411 {
1412     QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1413     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1414     QVERIFY(object != 0);
1415
1416     QCOMPARE(object->property("base").toReal(), 50.);
1417     QCOMPARE(object->property("test1").toReal(), 50.);
1418     QCOMPARE(object->property("test2").toReal(), 50.);
1419
1420     object->basicSignal();
1421
1422     QCOMPARE(object->property("base").toReal(), 200.);
1423     QCOMPARE(object->property("test1").toReal(), 200.);
1424     QCOMPARE(object->property("test2").toReal(), 200.);
1425
1426     object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1427
1428     QCOMPARE(object->property("base").toReal(), 400.);
1429     QCOMPARE(object->property("test1").toReal(), 400.);
1430     QCOMPARE(object->property("test2").toReal(), 400.);
1431
1432     delete object;
1433 }
1434
1435 /*
1436 Test that list properties can be iterated from ECMAScript
1437 */
1438 void tst_qdeclarativeecmascript::listProperties()
1439 {
1440     QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1441     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1442     QVERIFY(object != 0);
1443
1444     QCOMPARE(object->property("test1").toInt(), 21);
1445     QCOMPARE(object->property("test2").toInt(), 2);
1446     QCOMPARE(object->property("test3").toBool(), true);
1447     QCOMPARE(object->property("test4").toBool(), true);
1448
1449     delete object;
1450 }
1451
1452 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1453 {
1454     QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1455     QString url = component.url().toString();
1456
1457     QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1458
1459     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1460     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1461     QVERIFY(object != 0);
1462
1463     QCOMPARE(object->property("test").toBool(), false);
1464
1465     MyQmlObject object2;
1466     MyQmlObject object3;
1467     object2.setObjectProperty(&object3);
1468     object->setObjectProperty(&object2);
1469
1470     QCOMPARE(object->property("test").toBool(), true);
1471
1472     delete object;
1473 }
1474
1475 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1476 {
1477     QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1478     QString url = component.url().toString();
1479
1480     QString warning = component.url().toString() + ":6: Error: JS exception";
1481
1482     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1483     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1484     QVERIFY(object != 0);
1485     delete object;
1486 }
1487
1488 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1489 {
1490     QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1491     QString url = component.url().toString();
1492
1493     QString warning = component.url().toString() + ":5: Error: JS exception";
1494
1495     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1496     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1497     QVERIFY(object != 0);
1498     delete object;
1499 }
1500
1501 static int transientErrorsMsgCount = 0;
1502 static void transientErrorsMsgHandler(QtMsgType, const char *)
1503 {
1504     ++transientErrorsMsgCount;
1505 }
1506
1507 // Check that transient binding errors are not displayed
1508 void tst_qdeclarativeecmascript::transientErrors()
1509 {
1510     {
1511     QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1512
1513     transientErrorsMsgCount = 0;
1514     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1515
1516     QObject *object = component.create();
1517     QVERIFY(object != 0);
1518
1519     qInstallMsgHandler(old);
1520
1521     QCOMPARE(transientErrorsMsgCount, 0);
1522
1523     delete object;
1524     }
1525
1526     // One binding erroring multiple times, but then resolving
1527     {
1528     QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1529
1530     transientErrorsMsgCount = 0;
1531     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1532
1533     QObject *object = component.create();
1534     QVERIFY(object != 0);
1535
1536     qInstallMsgHandler(old);
1537
1538     QCOMPARE(transientErrorsMsgCount, 0);
1539
1540     delete object;
1541     }
1542 }
1543
1544 // Check that errors during shutdown are minimized
1545 void tst_qdeclarativeecmascript::shutdownErrors()
1546 {
1547     QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1548     QObject *object = component.create();
1549     QVERIFY(object != 0);
1550
1551     transientErrorsMsgCount = 0;
1552     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1553
1554     delete object;
1555
1556     qInstallMsgHandler(old);
1557     QCOMPARE(transientErrorsMsgCount, 0);
1558 }
1559
1560 void tst_qdeclarativeecmascript::compositePropertyType()
1561 {
1562     QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1563     QTest::ignoreMessage(QtDebugMsg, "hello world");
1564     QObject *object = qobject_cast<QObject *>(component.create());
1565     delete object;
1566 }
1567
1568 // QTBUG-5759
1569 void tst_qdeclarativeecmascript::jsObject()
1570 {
1571     QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1572     QObject *object = component.create();
1573     QVERIFY(object != 0);
1574
1575     QCOMPARE(object->property("test").toInt(), 92);
1576
1577     delete object;
1578 }
1579
1580 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1581 {
1582     {
1583     QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1584     QObject *object = component.create();
1585     QVERIFY(object != 0);
1586
1587     QCOMPARE(object->property("resettableProperty").toInt(), 92);
1588
1589     object->setProperty("setUndefined", true);
1590
1591     QCOMPARE(object->property("resettableProperty").toInt(), 13);
1592
1593     object->setProperty("setUndefined", false);
1594
1595     QCOMPARE(object->property("resettableProperty").toInt(), 92);
1596
1597     delete object;
1598     }
1599     {
1600     QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1601     QObject *object = component.create();
1602     QVERIFY(object != 0);
1603
1604     QCOMPARE(object->property("resettableProperty").toInt(), 19);
1605
1606     QMetaObject::invokeMethod(object, "doReset");
1607
1608     QCOMPARE(object->property("resettableProperty").toInt(), 13);
1609
1610     delete object;
1611     }
1612 }
1613
1614 // QTBUG-6781
1615 void tst_qdeclarativeecmascript::bug1()
1616 {
1617     QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1618     QObject *object = component.create();
1619     QVERIFY(object != 0);
1620
1621     QCOMPARE(object->property("test").toInt(), 14);
1622
1623     object->setProperty("a", 11);
1624
1625     QCOMPARE(object->property("test").toInt(), 3);
1626
1627     object->setProperty("b", true);
1628
1629     QCOMPARE(object->property("test").toInt(), 9);
1630
1631     delete object;
1632 }
1633
1634 void tst_qdeclarativeecmascript::bug2()
1635 {
1636     QDeclarativeComponent component(&engine);
1637     component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1638
1639     QObject *object = component.create();
1640     QVERIFY(object != 0);
1641
1642     delete object;
1643 }
1644
1645 // Don't crash in createObject when the component has errors.
1646 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1647 {
1648     QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1649     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1650     QVERIFY(object != 0);
1651
1652     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1653     QMetaObject::invokeMethod(object, "dontCrash");
1654     QObject *created = object->objectProperty();
1655     QVERIFY(created == 0);
1656
1657     delete object;
1658 }
1659
1660 //QTBUG-9367
1661 void tst_qdeclarativeecmascript::regExpBug()
1662 {
1663     QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1664     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1665     QVERIFY(object != 0);
1666     QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1667     delete object;
1668 }
1669
1670 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1671 {
1672     QString functionSource = QLatin1String("(function(object) { return ") + 
1673                              QLatin1String(source) + QLatin1String(" })");
1674     v8::TryCatch tc;
1675     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1676     if (tc.HasCaught())
1677         return false;
1678     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1679     if (function.IsEmpty())
1680         return false;
1681     v8::Handle<v8::Value> args[] = { o };
1682     function->Call(engine->global(), 1, args);
1683     return tc.HasCaught();
1684 }
1685
1686 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o, 
1687                                   const char *source, v8::Handle<v8::Value> result)
1688 {
1689     QString functionSource = QLatin1String("(function(object) { return ") + 
1690                              QLatin1String(source) + QLatin1String(" })");
1691     v8::TryCatch tc;
1692     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1693     if (tc.HasCaught())
1694         return false;
1695     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1696     if (function.IsEmpty())
1697         return false;
1698     v8::Handle<v8::Value> args[] = { o };
1699
1700     v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1701
1702     if (tc.HasCaught())
1703         return false;
1704
1705     return value->StrictEquals(result);
1706 }
1707
1708 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o, 
1709                                              const char *source)
1710 {
1711     QString functionSource = QLatin1String("(function(object) { return ") + 
1712                              QLatin1String(source) + QLatin1String(" })");
1713     v8::TryCatch tc;
1714     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1715     if (tc.HasCaught())
1716         return v8::Handle<v8::Value>();
1717     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1718     if (function.IsEmpty())
1719         return v8::Handle<v8::Value>();
1720     v8::Handle<v8::Value> args[] = { o };
1721
1722     v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1723
1724     if (tc.HasCaught())
1725         return v8::Handle<v8::Value>();
1726     return value;
1727 }
1728
1729 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1730 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1731 #define EVALUATE(source) evaluate(engine, object, source)
1732
1733 void tst_qdeclarativeecmascript::callQtInvokables()
1734 {
1735     MyInvokableObject o;
1736
1737     QDeclarativeEngine qmlengine;
1738     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1739     
1740     QV8Engine *engine = ep->v8engine();
1741
1742     v8::HandleScope handle_scope;
1743     v8::Context::Scope scope(engine->context());
1744
1745     v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1746
1747     // Non-existent methods
1748     o.reset();
1749     QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1750     QCOMPARE(o.error(), false);
1751     QCOMPARE(o.invoked(), -1);
1752     QCOMPARE(o.actuals().count(), 0);
1753
1754     o.reset();
1755     QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1756     QCOMPARE(o.error(), false);
1757     QCOMPARE(o.invoked(), -1);
1758     QCOMPARE(o.actuals().count(), 0);
1759
1760     // Insufficient arguments
1761     o.reset();
1762     QVERIFY(EVALUATE_ERROR("object.method_int()"));
1763     QCOMPARE(o.error(), false);
1764     QCOMPARE(o.invoked(), -1);
1765     QCOMPARE(o.actuals().count(), 0);
1766
1767     o.reset();
1768     QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1769     QCOMPARE(o.error(), false);
1770     QCOMPARE(o.invoked(), -1);
1771     QCOMPARE(o.actuals().count(), 0);
1772
1773     // Excessive arguments
1774     o.reset();
1775     QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1776     QCOMPARE(o.error(), false);
1777     QCOMPARE(o.invoked(), 8);
1778     QCOMPARE(o.actuals().count(), 1);
1779     QCOMPARE(o.actuals().at(0), QVariant(10));
1780
1781     o.reset();
1782     QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1783     QCOMPARE(o.error(), false);
1784     QCOMPARE(o.invoked(), 9);
1785     QCOMPARE(o.actuals().count(), 2);
1786     QCOMPARE(o.actuals().at(0), QVariant(10));
1787     QCOMPARE(o.actuals().at(1), QVariant(11));
1788
1789     // Test return types
1790     o.reset();
1791     QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1792     QCOMPARE(o.error(), false);
1793     QCOMPARE(o.invoked(), 0);
1794     QCOMPARE(o.actuals().count(), 0);
1795
1796     o.reset();
1797     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1798     QCOMPARE(o.error(), false);
1799     QCOMPARE(o.invoked(), 1);
1800     QCOMPARE(o.actuals().count(), 0);
1801
1802     o.reset();
1803     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1804     QCOMPARE(o.error(), false);
1805     QCOMPARE(o.invoked(), 2);
1806     QCOMPARE(o.actuals().count(), 0);
1807
1808     o.reset();
1809     {
1810     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1811     QVERIFY(!ret.IsEmpty());
1812     QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1813     QCOMPARE(o.error(), false);
1814     QCOMPARE(o.invoked(), 3);
1815     QCOMPARE(o.actuals().count(), 0);
1816     }
1817
1818     o.reset();
1819     {
1820     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1821     QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1822     QCOMPARE(o.error(), false);
1823     QCOMPARE(o.invoked(), 4);
1824     QCOMPARE(o.actuals().count(), 0);
1825     }
1826
1827     o.reset();
1828     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1829     QCOMPARE(o.error(), false);
1830     QCOMPARE(o.invoked(), 5);
1831     QCOMPARE(o.actuals().count(), 0);
1832
1833     o.reset();
1834     {
1835     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1836     QVERIFY(ret->IsString());
1837     QCOMPARE(engine->toString(ret), QString("Hello world"));
1838     QCOMPARE(o.error(), false);
1839     QCOMPARE(o.invoked(), 6);
1840     QCOMPARE(o.actuals().count(), 0);
1841     }
1842
1843     o.reset();
1844     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1845     QCOMPARE(o.error(), false);
1846     QCOMPARE(o.invoked(), 7);
1847     QCOMPARE(o.actuals().count(), 0);
1848
1849     // Test arg types
1850     o.reset();
1851     QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1852     QCOMPARE(o.error(), false);
1853     QCOMPARE(o.invoked(), 8);
1854     QCOMPARE(o.actuals().count(), 1);
1855     QCOMPARE(o.actuals().at(0), QVariant(94));
1856
1857     o.reset();
1858     QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1859     QCOMPARE(o.error(), false);
1860     QCOMPARE(o.invoked(), 8);
1861     QCOMPARE(o.actuals().count(), 1);
1862     QCOMPARE(o.actuals().at(0), QVariant(94));
1863
1864     o.reset();
1865     QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1866     QCOMPARE(o.error(), false);
1867     QCOMPARE(o.invoked(), 8);
1868     QCOMPARE(o.actuals().count(), 1);
1869     QCOMPARE(o.actuals().at(0), QVariant(0));
1870
1871     o.reset();
1872     QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1873     QCOMPARE(o.error(), false);
1874     QCOMPARE(o.invoked(), 8);
1875     QCOMPARE(o.actuals().count(), 1);
1876     QCOMPARE(o.actuals().at(0), QVariant(0));
1877
1878     o.reset();
1879     QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1880     QCOMPARE(o.error(), false);
1881     QCOMPARE(o.invoked(), 8);
1882     QCOMPARE(o.actuals().count(), 1);
1883     QCOMPARE(o.actuals().at(0), QVariant(0));
1884
1885     o.reset();
1886     QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1887     QCOMPARE(o.error(), false);
1888     QCOMPARE(o.invoked(), 8);
1889     QCOMPARE(o.actuals().count(), 1);
1890     QCOMPARE(o.actuals().at(0), QVariant(0));
1891
1892     o.reset();
1893     QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1894     QCOMPARE(o.error(), false);
1895     QCOMPARE(o.invoked(), 9);
1896     QCOMPARE(o.actuals().count(), 2);
1897     QCOMPARE(o.actuals().at(0), QVariant(122));
1898     QCOMPARE(o.actuals().at(1), QVariant(9));
1899
1900     o.reset();
1901     QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1902     QCOMPARE(o.error(), false);
1903     QCOMPARE(o.invoked(), 10);
1904     QCOMPARE(o.actuals().count(), 1);
1905     QCOMPARE(o.actuals().at(0), QVariant(94.3));
1906
1907     o.reset();
1908     QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1909     QCOMPARE(o.error(), false);
1910     QCOMPARE(o.invoked(), 10);
1911     QCOMPARE(o.actuals().count(), 1);
1912     QCOMPARE(o.actuals().at(0), QVariant(94.3));
1913
1914     o.reset();
1915     QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1916     QCOMPARE(o.error(), false);
1917     QCOMPARE(o.invoked(), 10);
1918     QCOMPARE(o.actuals().count(), 1);
1919     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1920
1921     o.reset();
1922     QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1923     QCOMPARE(o.error(), false);
1924     QCOMPARE(o.invoked(), 10);
1925     QCOMPARE(o.actuals().count(), 1);
1926     QCOMPARE(o.actuals().at(0), QVariant(0));
1927
1928     o.reset();
1929     QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1930     QCOMPARE(o.error(), false);
1931     QCOMPARE(o.invoked(), 10);
1932     QCOMPARE(o.actuals().count(), 1);
1933     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1934
1935     o.reset();
1936     QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1937     QCOMPARE(o.error(), false);
1938     QCOMPARE(o.invoked(), 10);
1939     QCOMPARE(o.actuals().count(), 1);
1940     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1941
1942     o.reset();
1943     QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1944     QCOMPARE(o.error(), false);
1945     QCOMPARE(o.invoked(), 11);
1946     QCOMPARE(o.actuals().count(), 1);
1947     QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1948
1949     o.reset();
1950     QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1951     QCOMPARE(o.error(), false);
1952     QCOMPARE(o.invoked(), 11);
1953     QCOMPARE(o.actuals().count(), 1);
1954     QCOMPARE(o.actuals().at(0), QVariant("19"));
1955
1956     o.reset();
1957     {
1958     QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1959     QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1960     QCOMPARE(o.error(), false);
1961     QCOMPARE(o.invoked(), 11);
1962     QCOMPARE(o.actuals().count(), 1);
1963     QCOMPARE(o.actuals().at(0), QVariant(expected));
1964     }
1965
1966     o.reset();
1967     QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1968     QCOMPARE(o.error(), false);
1969     QCOMPARE(o.invoked(), 11);
1970     QCOMPARE(o.actuals().count(), 1);
1971     QCOMPARE(o.actuals().at(0), QVariant(QString()));
1972
1973     o.reset();
1974     QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1975     QCOMPARE(o.error(), false);
1976     QCOMPARE(o.invoked(), 11);
1977     QCOMPARE(o.actuals().count(), 1);
1978     QCOMPARE(o.actuals().at(0), QVariant(QString()));
1979
1980     o.reset();
1981     QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1982     QCOMPARE(o.error(), false);
1983     QCOMPARE(o.invoked(), 12);
1984     QCOMPARE(o.actuals().count(), 1);
1985     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1986
1987     o.reset();
1988     QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1989     QCOMPARE(o.error(), false);
1990     QCOMPARE(o.invoked(), 12);
1991     QCOMPARE(o.actuals().count(), 1);
1992     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1993
1994     o.reset();
1995     QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1996     QCOMPARE(o.error(), false);
1997     QCOMPARE(o.invoked(), 12);
1998     QCOMPARE(o.actuals().count(), 1);
1999     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2000
2001     o.reset();
2002     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2003     QCOMPARE(o.error(), false);
2004     QCOMPARE(o.invoked(), 12);
2005     QCOMPARE(o.actuals().count(), 1);
2006     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2007
2008     o.reset();
2009     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2010     QCOMPARE(o.error(), false);
2011     QCOMPARE(o.invoked(), 12);
2012     QCOMPARE(o.actuals().count(), 1);
2013     QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2014
2015     o.reset();
2016     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2017     QCOMPARE(o.error(), false);
2018     QCOMPARE(o.invoked(), 12);
2019     QCOMPARE(o.actuals().count(), 1);
2020     QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2021
2022     o.reset();
2023     QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2024     QCOMPARE(o.error(), false);
2025     QCOMPARE(o.invoked(), 13);
2026     QCOMPARE(o.actuals().count(), 1);
2027     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2028
2029     o.reset();
2030     QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2031     QCOMPARE(o.error(), false);
2032     QCOMPARE(o.invoked(), 13);
2033     QCOMPARE(o.actuals().count(), 1);
2034     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2035
2036     o.reset();
2037     QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2038     QCOMPARE(o.error(), false);
2039     QCOMPARE(o.invoked(), 13);
2040     QCOMPARE(o.actuals().count(), 1);
2041     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2042
2043     o.reset();
2044     QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2045     QCOMPARE(o.error(), false);
2046     QCOMPARE(o.invoked(), 13);
2047     QCOMPARE(o.actuals().count(), 1);
2048     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2049
2050     o.reset();
2051     QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2052     QCOMPARE(o.error(), false);
2053     QCOMPARE(o.invoked(), 13);
2054     QCOMPARE(o.actuals().count(), 1);
2055     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2056
2057     o.reset();
2058     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2059     QCOMPARE(o.error(), false);
2060     QCOMPARE(o.invoked(), 14);
2061     QCOMPARE(o.actuals().count(), 1);
2062     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2063
2064     o.reset();
2065     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2066     QCOMPARE(o.error(), false);
2067     QCOMPARE(o.invoked(), 14);
2068     QCOMPARE(o.actuals().count(), 1);
2069     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2070
2071     o.reset();
2072     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2073     QCOMPARE(o.error(), false);
2074     QCOMPARE(o.invoked(), 14);
2075     QCOMPARE(o.actuals().count(), 1);
2076     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2077
2078     o.reset();
2079     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2080     QCOMPARE(o.error(), false);
2081     QCOMPARE(o.invoked(), 14);
2082     QCOMPARE(o.actuals().count(), 1);
2083     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2084
2085     o.reset();
2086     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2087     QCOMPARE(o.error(), false);
2088     QCOMPARE(o.invoked(), 15);
2089     QCOMPARE(o.actuals().count(), 2);
2090     QCOMPARE(o.actuals().at(0), QVariant(4));
2091     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2092
2093     o.reset();
2094     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2095     QCOMPARE(o.error(), false);
2096     QCOMPARE(o.invoked(), 15);
2097     QCOMPARE(o.actuals().count(), 2);
2098     QCOMPARE(o.actuals().at(0), QVariant(8));
2099     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2100
2101     o.reset();
2102     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2103     QCOMPARE(o.error(), false);
2104     QCOMPARE(o.invoked(), 15);
2105     QCOMPARE(o.actuals().count(), 2);
2106     QCOMPARE(o.actuals().at(0), QVariant(3));
2107     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2108
2109     o.reset();
2110     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2111     QCOMPARE(o.error(), false);
2112     QCOMPARE(o.invoked(), 15);
2113     QCOMPARE(o.actuals().count(), 2);
2114     QCOMPARE(o.actuals().at(0), QVariant(44));
2115     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2116
2117     o.reset();
2118     QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2119     QCOMPARE(o.error(), false);
2120     QCOMPARE(o.invoked(), -1);
2121     QCOMPARE(o.actuals().count(), 0);
2122
2123     o.reset();
2124     QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2125     QCOMPARE(o.error(), false);
2126     QCOMPARE(o.invoked(), 16);
2127     QCOMPARE(o.actuals().count(), 1);
2128     QCOMPARE(o.actuals().at(0), QVariant(10));
2129
2130     o.reset();
2131     QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2132     QCOMPARE(o.error(), false);
2133     QCOMPARE(o.invoked(), 17);
2134     QCOMPARE(o.actuals().count(), 2);
2135     QCOMPARE(o.actuals().at(0), QVariant(10));
2136     QCOMPARE(o.actuals().at(1), QVariant(11));
2137
2138     o.reset();
2139     QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2140     QCOMPARE(o.error(), false);
2141     QCOMPARE(o.invoked(), 18);
2142     QCOMPARE(o.actuals().count(), 1);
2143     QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2144
2145     o.reset();
2146     QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2147     QCOMPARE(o.error(), false);
2148     QCOMPARE(o.invoked(), 19);
2149     QCOMPARE(o.actuals().count(), 1);
2150     QCOMPARE(o.actuals().at(0), QVariant(9));
2151
2152     o.reset();
2153     QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2154     QCOMPARE(o.error(), false);
2155     QCOMPARE(o.invoked(), 20);
2156     QCOMPARE(o.actuals().count(), 2);
2157     QCOMPARE(o.actuals().at(0), QVariant(10));
2158     QCOMPARE(o.actuals().at(1), QVariant(19));
2159
2160     o.reset();
2161     QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2162     QCOMPARE(o.error(), false);
2163     QCOMPARE(o.invoked(), 20);
2164     QCOMPARE(o.actuals().count(), 2);
2165     QCOMPARE(o.actuals().at(0), QVariant(10));
2166     QCOMPARE(o.actuals().at(1), QVariant(13));
2167
2168     o.reset();
2169     QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2170     QCOMPARE(o.error(), false);
2171     QCOMPARE(o.invoked(), -3);
2172     QCOMPARE(o.actuals().count(), 1);
2173     QCOMPARE(o.actuals().at(0), QVariant(9));
2174
2175     o.reset();
2176     QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2177     QCOMPARE(o.error(), false);
2178     QCOMPARE(o.invoked(), 21);
2179     QCOMPARE(o.actuals().count(), 2);
2180     QCOMPARE(o.actuals().at(0), QVariant(9));
2181     QCOMPARE(o.actuals().at(1), QVariant());
2182
2183     o.reset();
2184     QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2185     QCOMPARE(o.error(), false);
2186     QCOMPARE(o.invoked(), 21);
2187     QCOMPARE(o.actuals().count(), 2);
2188     QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2189     QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2190 }
2191
2192 // QTBUG-13047 (check that you can pass registered object types as args)
2193 void tst_qdeclarativeecmascript::invokableObjectArg()
2194 {
2195     QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2196
2197     QObject *o = component.create();
2198     QVERIFY(o);
2199     MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2200     QVERIFY(qmlobject);
2201     QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2202
2203     delete o;
2204 }
2205
2206 // QTBUG-13047 (check that you can return registered object types from methods)
2207 void tst_qdeclarativeecmascript::invokableObjectRet()
2208 {
2209     QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2210
2211     QObject *o = component.create();
2212     QVERIFY(o);
2213     QCOMPARE(o->property("test").toBool(), true);
2214     delete o;
2215 }
2216
2217 // QTBUG-5675
2218 void tst_qdeclarativeecmascript::listToVariant()
2219 {
2220     QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2221
2222     MyQmlContainer container;
2223
2224     QDeclarativeContext context(engine.rootContext());
2225     context.setContextObject(&container);
2226
2227     QObject *object = component.create(&context);
2228     QVERIFY(object != 0);
2229
2230     QVariant v = object->property("test");
2231     QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2232     QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2233
2234     delete object;
2235 }
2236
2237 // QTBUG-16316
2238 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2239 void tst_qdeclarativeecmascript::listAssignment()
2240 {
2241     QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2242     QObject *obj = component.create();
2243     QCOMPARE(obj->property("list1length").toInt(), 2);
2244     QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2245     QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2246     QCOMPARE(list1.count(&list1), list2.count(&list2));
2247     QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2248     QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2249     delete obj;
2250 }
2251
2252 // QTBUG-7957
2253 void tst_qdeclarativeecmascript::multiEngineObject()
2254 {
2255     MyQmlObject obj;
2256     obj.setStringProperty("Howdy planet");
2257
2258     QDeclarativeEngine e1;
2259     e1.rootContext()->setContextProperty("thing", &obj);
2260     QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2261
2262     QDeclarativeEngine e2;
2263     e2.rootContext()->setContextProperty("thing", &obj);
2264     QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2265
2266     QObject *o1 = c1.create();
2267     QObject *o2 = c2.create();
2268
2269     QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2270     QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2271
2272     delete o2;
2273     delete o1;
2274 }
2275
2276 // Test that references to QObjects are cleanup when the object is destroyed
2277 void tst_qdeclarativeecmascript::deletedObject()
2278 {
2279     QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2280
2281     QObject *object = component.create();
2282
2283     QCOMPARE(object->property("test1").toBool(), true);
2284     QCOMPARE(object->property("test2").toBool(), true);
2285     QCOMPARE(object->property("test3").toBool(), true);
2286     QCOMPARE(object->property("test4").toBool(), true);
2287
2288     delete object;
2289 }
2290
2291 void tst_qdeclarativeecmascript::attachedPropertyScope()
2292 {
2293     QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2294
2295     QObject *object = component.create();
2296     QVERIFY(object != 0);
2297
2298     MyQmlAttachedObject *attached = 
2299         qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2300     QVERIFY(attached != 0);
2301
2302     QCOMPARE(object->property("value2").toInt(), 0);
2303
2304     attached->emitMySignal();
2305
2306     QCOMPARE(object->property("value2").toInt(), 9);
2307
2308     delete object;
2309 }
2310
2311 void tst_qdeclarativeecmascript::scriptConnect()
2312 {
2313     {
2314         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2315
2316         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2317         QVERIFY(object != 0);
2318
2319         QCOMPARE(object->property("test").toBool(), false);
2320         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2321         QCOMPARE(object->property("test").toBool(), true);
2322
2323         delete object;
2324     }
2325
2326     {
2327         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2328
2329         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2330         QVERIFY(object != 0);
2331
2332         QCOMPARE(object->property("test").toBool(), false);
2333         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2334         QCOMPARE(object->property("test").toBool(), true);
2335
2336         delete object;
2337     }
2338
2339     {
2340         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2341
2342         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2343         QVERIFY(object != 0);
2344
2345         QCOMPARE(object->property("test").toBool(), false);
2346         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2347         QCOMPARE(object->property("test").toBool(), true);
2348
2349         delete object;
2350     }
2351
2352     {
2353         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2354
2355         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2356         QVERIFY(object != 0);
2357
2358         QCOMPARE(object->methodCalled(), false);
2359         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2360         QCOMPARE(object->methodCalled(), true);
2361
2362         delete object;
2363     }
2364
2365     {
2366         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2367
2368         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2369         QVERIFY(object != 0);
2370
2371         QCOMPARE(object->methodCalled(), false);
2372         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2373         QCOMPARE(object->methodCalled(), true);
2374
2375         delete object;
2376     }
2377
2378     {
2379         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2380
2381         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2382         QVERIFY(object != 0);
2383
2384         QCOMPARE(object->property("test").toInt(), 0);
2385         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2386         QCOMPARE(object->property("test").toInt(), 2);
2387
2388         delete object;
2389     }
2390 }
2391
2392 void tst_qdeclarativeecmascript::scriptDisconnect()
2393 {
2394     {
2395         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2396
2397         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2398         QVERIFY(object != 0);
2399
2400         QCOMPARE(object->property("test").toInt(), 0);
2401         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2402         QCOMPARE(object->property("test").toInt(), 1);
2403         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2404         QCOMPARE(object->property("test").toInt(), 2);
2405         emit object->basicSignal();
2406         QCOMPARE(object->property("test").toInt(), 2);
2407         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2408         QCOMPARE(object->property("test").toInt(), 2);
2409
2410         delete object;
2411     }
2412
2413     {
2414         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2415
2416         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2417         QVERIFY(object != 0);
2418
2419         QCOMPARE(object->property("test").toInt(), 0);
2420         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2421         QCOMPARE(object->property("test").toInt(), 1);
2422         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2423         QCOMPARE(object->property("test").toInt(), 2);
2424         emit object->basicSignal();
2425         QCOMPARE(object->property("test").toInt(), 2);
2426         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2427         QCOMPARE(object->property("test").toInt(), 2);
2428
2429         delete object;
2430     }
2431
2432     {
2433         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2434
2435         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2436         QVERIFY(object != 0);
2437
2438         QCOMPARE(object->property("test").toInt(), 0);
2439         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2440         QCOMPARE(object->property("test").toInt(), 1);
2441         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2442         QCOMPARE(object->property("test").toInt(), 2);
2443         emit object->basicSignal();
2444         QCOMPARE(object->property("test").toInt(), 2);
2445         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2446         QCOMPARE(object->property("test").toInt(), 3);
2447
2448         delete object;
2449     }
2450     {
2451         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2452
2453         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2454         QVERIFY(object != 0);
2455
2456         QCOMPARE(object->property("test").toInt(), 0);
2457         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2458         QCOMPARE(object->property("test").toInt(), 1);
2459         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2460         QCOMPARE(object->property("test").toInt(), 2);
2461         emit object->basicSignal();
2462         QCOMPARE(object->property("test").toInt(), 2);
2463         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2464         QCOMPARE(object->property("test").toInt(), 3);
2465
2466         delete object;
2467     }
2468 }
2469
2470 class OwnershipObject : public QObject
2471 {
2472     Q_OBJECT
2473 public:
2474     OwnershipObject() { object = new QObject; }
2475
2476     QPointer<QObject> object;
2477
2478 public slots:
2479     QObject *getObject() { return object; }
2480 };
2481
2482 void tst_qdeclarativeecmascript::ownership()
2483 {
2484     OwnershipObject own;
2485     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2486     context->setContextObject(&own);
2487
2488     {
2489         QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2490
2491         QVERIFY(own.object != 0);
2492
2493         QObject *object = component.create(context);
2494
2495         engine.collectGarbage();
2496
2497         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2498
2499         QVERIFY(own.object == 0);
2500
2501         delete object;
2502     }
2503
2504     own.object = new QObject(&own);
2505
2506     {
2507         QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2508
2509         QVERIFY(own.object != 0);
2510
2511         QObject *object = component.create(context);
2512         
2513         engine.collectGarbage();
2514
2515         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2516
2517         QVERIFY(own.object != 0);
2518
2519         delete object;
2520     }
2521
2522     delete context;
2523 }
2524
2525 class CppOwnershipReturnValue : public QObject
2526 {
2527     Q_OBJECT
2528 public:
2529     CppOwnershipReturnValue() : value(0) {}
2530     ~CppOwnershipReturnValue() { delete value; }
2531
2532     Q_INVOKABLE QObject *create() {
2533         value = new QObject;
2534         QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2535         return value;
2536     }
2537
2538     Q_INVOKABLE MyQmlObject *createQmlObject() {
2539         MyQmlObject *rv = new MyQmlObject;
2540         value = rv;
2541         return rv;
2542     }
2543
2544     QPointer<QObject> value;
2545 };
2546
2547 // QTBUG-15695.  
2548 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2549 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2550 {
2551     CppOwnershipReturnValue source;
2552
2553     {
2554     QDeclarativeEngine engine;
2555     engine.rootContext()->setContextProperty("source", &source);
2556
2557     QVERIFY(source.value == 0);
2558
2559     QDeclarativeComponent component(&engine);
2560     component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2561
2562     QObject *object = component.create();
2563
2564     QVERIFY(object != 0);
2565     QVERIFY(source.value != 0);
2566
2567     delete object;
2568     }
2569
2570     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2571
2572     QVERIFY(source.value != 0);
2573 }
2574
2575 // QTBUG-15697
2576 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2577 {
2578     CppOwnershipReturnValue source;
2579
2580     {
2581     QDeclarativeEngine engine;
2582     engine.rootContext()->setContextProperty("source", &source);
2583
2584     QVERIFY(source.value == 0);
2585
2586     QDeclarativeComponent component(&engine);
2587     component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2588
2589     QObject *object = component.create();
2590
2591     QVERIFY(object != 0);
2592     QVERIFY(source.value != 0);
2593
2594     delete object;
2595     }
2596
2597     engine.collectGarbage();
2598     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2599
2600     QVERIFY(source.value == 0);
2601 }
2602
2603 class QListQObjectMethodsObject : public QObject
2604 {
2605     Q_OBJECT
2606 public:
2607     QListQObjectMethodsObject() {
2608         m_objects.append(new MyQmlObject());
2609         m_objects.append(new MyQmlObject());
2610     }
2611
2612     ~QListQObjectMethodsObject() {
2613         qDeleteAll(m_objects);
2614     }
2615
2616 public slots:
2617     QList<QObject *> getObjects() { return m_objects; }
2618
2619 private:
2620     QList<QObject *> m_objects;
2621 };
2622
2623 // Tests that returning a QList<QObject*> from a method works
2624 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2625 {
2626     QListQObjectMethodsObject obj;
2627     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2628     context->setContextObject(&obj);
2629
2630     QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2631
2632     QObject *object = component.create(context);
2633
2634     QCOMPARE(object->property("test").toInt(), 2);
2635     QCOMPARE(object->property("test2").toBool(), true);
2636
2637     delete object;
2638     delete context;
2639 }
2640
2641 // QTBUG-9205
2642 void tst_qdeclarativeecmascript::strictlyEquals()
2643 {
2644     QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2645
2646     QObject *object = component.create();
2647     QVERIFY(object != 0);
2648
2649     QCOMPARE(object->property("test1").toBool(), true);
2650     QCOMPARE(object->property("test2").toBool(), true);
2651     QCOMPARE(object->property("test3").toBool(), true);
2652     QCOMPARE(object->property("test4").toBool(), true);
2653     QCOMPARE(object->property("test5").toBool(), true);
2654     QCOMPARE(object->property("test6").toBool(), true);
2655     QCOMPARE(object->property("test7").toBool(), true);
2656     QCOMPARE(object->property("test8").toBool(), true);
2657
2658     delete object;
2659 }
2660
2661 void tst_qdeclarativeecmascript::compiled()
2662 {
2663     QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2664
2665     QObject *object = component.create();
2666     QVERIFY(object != 0);
2667
2668     QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2669     QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2670     QCOMPARE(object->property("test3").toBool(), true);
2671     QCOMPARE(object->property("test4").toBool(), false);
2672     QCOMPARE(object->property("test5").toBool(), false);
2673     QCOMPARE(object->property("test6").toBool(), true);
2674
2675     QCOMPARE(object->property("test7").toInt(), 185);
2676     QCOMPARE(object->property("test8").toInt(), 167);
2677     QCOMPARE(object->property("test9").toBool(), true);
2678     QCOMPARE(object->property("test10").toBool(), false);
2679     QCOMPARE(object->property("test11").toBool(), false);
2680     QCOMPARE(object->property("test12").toBool(), true);
2681
2682     QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2683     QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2684     QCOMPARE(object->property("test15").toBool(), false);
2685     QCOMPARE(object->property("test16").toBool(), true);
2686
2687     QCOMPARE(object->property("test17").toInt(), 5);
2688     QCOMPARE(object->property("test18").toReal(), qreal(176));
2689     QCOMPARE(object->property("test19").toInt(), 7);
2690     QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2691     QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2692     QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2693     QCOMPARE(object->property("test23").toBool(), true);
2694     QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2695     QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2696
2697     delete object;
2698 }
2699
2700 // Test that numbers assigned in bindings as strings work consistently
2701 void tst_qdeclarativeecmascript::numberAssignment()
2702 {
2703     QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2704
2705     QObject *object = component.create();
2706     QVERIFY(object != 0);
2707
2708     QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2709     QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2710     QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2711     QCOMPARE(object->property("test3"), QVariant((qreal)6));
2712     QCOMPARE(object->property("test4"), QVariant((qreal)6));
2713
2714     QCOMPARE(object->property("test5"), QVariant((int)7));
2715     QCOMPARE(object->property("test6"), QVariant((int)7));
2716     QCOMPARE(object->property("test7"), QVariant((int)6));
2717     QCOMPARE(object->property("test8"), QVariant((int)6));
2718
2719     QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2720     QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2721     QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2722     QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2723
2724     delete object;
2725 }
2726
2727 void tst_qdeclarativeecmascript::propertySplicing()
2728 {
2729     QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2730
2731     QObject *object = component.create();
2732     QVERIFY(object != 0);
2733
2734     QCOMPARE(object->property("test").toBool(), true);
2735
2736     delete object;
2737 }
2738
2739 // QTBUG-16683
2740 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2741 {
2742     QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2743
2744     MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2745     QVERIFY(object != 0);
2746
2747     MyQmlObject::MyType type;
2748     type.value = 0x8971123;
2749     emit object->signalWithUnknownType(type);
2750
2751     MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2752
2753     QCOMPARE(result.value, type.value);
2754
2755
2756     delete object;
2757 }
2758
2759 void tst_qdeclarativeecmascript::moduleApi_data()
2760 {
2761     QTest::addColumn<QUrl>("testfile");
2762     QTest::addColumn<QString>("errorMessage");
2763     QTest::addColumn<QStringList>("warningMessages");
2764     QTest::addColumn<QStringList>("readProperties");
2765     QTest::addColumn<QVariantList>("readExpectedValues");
2766     QTest::addColumn<QStringList>("writeProperties");
2767     QTest::addColumn<QVariantList>("writeValues");
2768     QTest::addColumn<QStringList>("readBackProperties");
2769     QTest::addColumn<QVariantList>("readBackExpectedValues");
2770
2771     QTest::newRow("qobject, register + read + method")
2772             << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2773             << QString()
2774             << QStringList()
2775             << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2776                    << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2777             << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2778             << QStringList()
2779             << QVariantList()
2780             << QStringList()
2781             << QVariantList();
2782
2783     QTest::newRow("script, register + read")
2784             << TEST_FILE("moduleapi/scriptModuleApi.qml")
2785             << QString()
2786             << QStringList()
2787             << (QStringList() << "scriptTest")
2788             << (QVariantList() << 13)
2789             << QStringList()
2790             << QVariantList()
2791             << QStringList()
2792             << QVariantList();
2793
2794     QTest::newRow("qobject, caching + read")
2795             << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2796             << QString()
2797             << QStringList()
2798             << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2799             << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2800             << QStringList()
2801             << QVariantList()
2802             << QStringList()
2803             << QVariantList();
2804
2805     QTest::newRow("script, caching + read")
2806             << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2807             << QString()
2808             << QStringList()
2809             << (QStringList() << "scriptTest")
2810             << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2811             << QStringList()
2812             << QVariantList()
2813             << QStringList()
2814             << QVariantList();
2815
2816     QTest::newRow("qobject, writing + readonly constraints")
2817             << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2818             << QString()
2819             << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2820             << (QStringList() << "readOnlyProperty" << "writableProperty")
2821             << (QVariantList() << 20 << 50)
2822             << (QStringList() << "firstProperty" << "writableProperty")
2823             << (QVariantList() << 30 << 30)
2824             << (QStringList() << "readOnlyProperty" << "writableProperty")
2825             << (QVariantList() << 20 << 30);
2826
2827     QTest::newRow("script, writing + readonly constraints")
2828             << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2829             << QString()
2830             << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2831             << (QStringList() << "readBack" << "unchanged")
2832             << (QVariantList() << 13 << 42)
2833             << (QStringList() << "firstProperty" << "secondProperty")
2834             << (QVariantList() << 30 << 30)
2835             << (QStringList() << "readBack" << "unchanged")
2836             << (QVariantList() << 30 << 42);
2837
2838     QTest::newRow("qobject module API enum values in JS")
2839             << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2840             << QString()
2841             << QStringList()
2842             << (QStringList() << "enumValue" << "enumMethod")
2843             << (QVariantList() << 42 << 30)
2844             << QStringList()
2845             << QVariantList()
2846             << QStringList()
2847             << QVariantList();
2848
2849     QTest::newRow("qobject, invalid major version fail")
2850             << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2851             << QString("QDeclarativeComponent: Component is not ready")
2852             << QStringList()
2853             << QStringList()
2854             << QVariantList()
2855             << QStringList()
2856             << QVariantList()
2857             << QStringList()
2858             << QVariantList();
2859
2860     QTest::newRow("qobject, invalid minor version fail")
2861             << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2862             << QString("QDeclarativeComponent: Component is not ready")
2863             << QStringList()
2864             << QStringList()
2865             << QVariantList()
2866             << QStringList()
2867             << QVariantList()
2868             << QStringList()
2869             << QVariantList();
2870 }
2871
2872 void tst_qdeclarativeecmascript::moduleApi()
2873 {
2874     QFETCH(QUrl, testfile);
2875     QFETCH(QString, errorMessage);
2876     QFETCH(QStringList, warningMessages);
2877     QFETCH(QStringList, readProperties);
2878     QFETCH(QVariantList, readExpectedValues);
2879     QFETCH(QStringList, writeProperties);
2880     QFETCH(QVariantList, writeValues);
2881     QFETCH(QStringList, readBackProperties);
2882     QFETCH(QVariantList, readBackExpectedValues);
2883
2884     QDeclarativeComponent component(&engine, testfile);
2885
2886     if (!errorMessage.isEmpty())
2887         QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
2888
2889     if (warningMessages.size())
2890         foreach (const QString &warning, warningMessages)
2891             QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
2892
2893     QObject *object = component.create();
2894     if (!errorMessage.isEmpty()) {
2895         QVERIFY(object == 0);
2896     } else {
2897         QVERIFY(object != 0);
2898         for (int i = 0; i < readProperties.size(); ++i)
2899             QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
2900         for (int i = 0; i < writeProperties.size(); ++i)
2901             QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
2902         for (int i = 0; i < readBackProperties.size(); ++i)
2903             QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
2904         delete object;
2905     }
2906 }
2907
2908 void tst_qdeclarativeecmascript::importScripts()
2909 {
2910     QObject *object = 0;
2911
2912     // first, ensure that the required behaviour works.
2913     QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2914     object = component.create();
2915     QVERIFY(object != 0);
2916     QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2917     QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2918     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2919     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2920     delete object;
2921
2922     QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2923     object = componentTwo.create();
2924     QVERIFY(object != 0);
2925     QCOMPARE(object->property("componentError"), QVariant(5));
2926     delete object;
2927
2928     // then, ensure that unintended behaviour does not work.
2929     QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2930     QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2931     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2932     object = failOneComponent.create();
2933     QVERIFY(object != 0);
2934     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2935     delete object;
2936     QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2937     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2938     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2939     object = failTwoComponent.create();
2940     QVERIFY(object != 0);
2941     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2942     delete object;
2943     QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2944     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2945     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2946     object = failThreeComponent.create();
2947     QVERIFY(object != 0);
2948     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2949     delete object;
2950     QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2951     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2952     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2953     object = failFourComponent.create();
2954     QVERIFY(object != 0);
2955     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2956     delete object;
2957     QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2958     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2959     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2960     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2961     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2962     object = failFiveComponent.create();
2963     QVERIFY(object != 0);
2964     QCOMPARE(object->property("componentError"), QVariant(0));
2965     delete object;
2966
2967     // also, test that importing scripts with .pragma library works as required
2968     QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2969     object = pragmaLibraryComponent.create();
2970     QVERIFY(object != 0);
2971     QCOMPARE(object->property("testValue"), QVariant(31));
2972     delete object;
2973
2974     // and that .pragma library scripts don't inherit imports from any .qml file
2975     QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2976     object = pragmaLibraryComponentTwo.create();
2977     QVERIFY(object != 0);
2978     QCOMPARE(object->property("testValue"), QVariant(0));
2979     delete object;
2980 }
2981
2982 void tst_qdeclarativeecmascript::scarceResources()
2983 {
2984     QPixmap origPixmap(100, 100);
2985     origPixmap.fill(Qt::blue);
2986
2987     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2988     ScarceResourceObject *eo = 0;
2989     QObject *object = 0;
2990
2991     // in the following three cases, the instance created from the component
2992     // has a property which is a copy of the scarce resource; hence, the
2993     // resource should NOT be detached prior to deletion of the object instance,
2994     // unless the resource is destroyed explicitly.
2995     QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2996     object = component.create();
2997     QVERIFY(object != 0);
2998     QVERIFY(object->property("scarceResourceCopy").isValid());
2999     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3000     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3001     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3002     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3003     delete object;
3004
3005     QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3006     object = componentTwo.create();
3007     QVERIFY(object != 0);
3008     QVERIFY(object->property("scarceResourceCopy").isValid());
3009     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3010     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3011     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3012     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3013     delete object;
3014
3015     QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3016     object = componentThree.create();
3017     QVERIFY(object != 0);
3018     QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3019     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3020     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3021     QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3022     delete object;
3023
3024     // in the following three cases, no other copy should exist in memory,
3025     // and so it should be detached (unless explicitly preserved).
3026     QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3027     object = componentFour.create();
3028     QVERIFY(object != 0);
3029     QVERIFY(object->property("scarceResourceTest").isValid());
3030     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3031     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3032     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3033     QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3034     delete object;
3035
3036     QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3037     object = componentFive.create();
3038     QVERIFY(object != 0);
3039     QVERIFY(object->property("scarceResourceTest").isValid());
3040     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3041     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3042     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3043     QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3044     delete object;
3045
3046     QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3047     object = componentSix.create();
3048     QVERIFY(object != 0);
3049     QVERIFY(object->property("scarceResourceTest").isValid());
3050     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3051     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3052     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3053     QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3054     delete object;
3055
3056     // test that scarce resources are handled correctly for imports
3057     QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3058     object = componentSeven.create();
3059     QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3060     QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3061     delete object;
3062
3063     QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3064     object = componentEight.create();
3065     QVERIFY(object != 0);
3066     QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3067     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3068     delete object;
3069
3070     QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3071     object = componentNine.create();
3072     QVERIFY(object != 0);
3073     QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3074     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3075     QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3076     QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3077     QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3078     QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3079     delete object;
3080
3081     // test that scarce resources are handled properly in signal invocation
3082     QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3083     object = componentTen.create();
3084     QVERIFY(object != 0);
3085     QObject *srsc = object->findChild<QObject*>("srsc");
3086     QVERIFY(srsc);
3087     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3088     QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3089     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3090     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3091     QMetaObject::invokeMethod(srsc, "testSignal");
3092     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3093     QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3094     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3095     QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3096     QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3097     QVERIFY(srsc->property("scarceResourceCopy").isValid());
3098     QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3099     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3100     QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3101     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3102     delete object;
3103
3104     // test that scarce resources are handled properly from js functions in qml files
3105     QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3106     object = componentEleven.create();
3107     QVERIFY(object != 0);
3108     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3109     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3110     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3111     QMetaObject::invokeMethod(object, "retrieveScarceResource");
3112     QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3113     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3114     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3115     QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3116     QMetaObject::invokeMethod(object, "releaseScarceResource");
3117     QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3118     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3119     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3120     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3121     delete object;
3122
3123     // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3124     QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3125     object = componentTwelve.create();
3126     QVERIFY(object != 0);
3127     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3128     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3129     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3130     QString srp_name = object->property("srp_name").toString();
3131     QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3132     QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3133     QMetaObject::invokeMethod(object, "retrieveScarceResource");
3134     QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3135     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3136     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3137     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3138     delete object;
3139 }
3140
3141 void tst_qdeclarativeecmascript::propertyChangeSlots()
3142 {
3143     // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3144     QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3145     QObject *object = component.create();
3146     QVERIFY(object != 0);
3147     delete object;
3148
3149     // ensure that invalid property names fail properly.
3150     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3151     QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3152     QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3153     QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3154     object = e1.create();
3155     QVERIFY(object == 0);
3156     delete object;
3157
3158     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3159     QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3160     expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3161     QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3162     object = e2.create();
3163     QVERIFY(object == 0);
3164     delete object;
3165
3166     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3167     QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3168     expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3169     QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3170     object = e3.create();
3171     QVERIFY(object == 0);
3172     delete object;
3173
3174     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3175     QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3176     expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3177     QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3178     object = e4.create();
3179     QVERIFY(object == 0);
3180     delete object;
3181 }
3182
3183 // Ensure that QObject type conversion works on binding assignment
3184 void tst_qdeclarativeecmascript::elementAssign()
3185 {
3186     QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3187
3188     QObject *object = component.create();
3189     QVERIFY(object != 0);
3190
3191     QCOMPARE(object->property("test").toBool(), true);
3192
3193     delete object;
3194 }
3195
3196 // QTBUG-12457
3197 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3198 {
3199     QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3200
3201     QObject *object = component.create();
3202     QVERIFY(object != 0);
3203
3204     QCOMPARE(object->property("test").toBool(), true);
3205
3206     delete object;
3207 }
3208
3209 // QTBUG-20242
3210 void tst_qdeclarativeecmascript::booleanConversion()
3211 {
3212     QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3213
3214     QObject *object = component.create();
3215     QVERIFY(object != 0);
3216
3217     QCOMPARE(object->property("test_true1").toBool(), true);
3218     QCOMPARE(object->property("test_true2").toBool(), true);
3219     QCOMPARE(object->property("test_true3").toBool(), true);
3220     QCOMPARE(object->property("test_true4").toBool(), true);
3221     QCOMPARE(object->property("test_true5").toBool(), true);
3222
3223     QCOMPARE(object->property("test_false1").toBool(), false);
3224     QCOMPARE(object->property("test_false2").toBool(), false);
3225     QCOMPARE(object->property("test_false3").toBool(), false);
3226
3227     delete object;
3228 }
3229
3230 void tst_qdeclarativeecmascript::handleReferenceManagement()
3231 {
3232
3233     int dtorCount = 0;
3234     {
3235         // Linear QObject reference
3236         QDeclarativeEngine hrmEngine;
3237         QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3238         QObject *object = component.create();
3239         QVERIFY(object != 0);
3240         CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3241         cro->setDtorCount(&dtorCount);
3242         QMetaObject::invokeMethod(object, "createReference");
3243         QMetaObject::invokeMethod(object, "performGc");
3244         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3245         QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3246         delete object;
3247         hrmEngine.collectGarbage();
3248         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3249         QCOMPARE(dtorCount, 3);
3250     }
3251
3252     dtorCount = 0;
3253     {
3254         // Circular QObject reference
3255         QDeclarativeEngine hrmEngine;
3256         QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3257         QObject *object = component.create();
3258         QVERIFY(object != 0);
3259         CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3260         cro->setDtorCount(&dtorCount);
3261         QMetaObject::invokeMethod(object, "circularReference");
3262         QMetaObject::invokeMethod(object, "performGc");
3263         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3264         QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3265         delete object;
3266         hrmEngine.collectGarbage();
3267         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3268         QCOMPARE(dtorCount, 3);
3269     }
3270
3271     dtorCount = 0;
3272     {
3273         // Linear handle reference
3274         QDeclarativeEngine hrmEngine;
3275         QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3276         QObject *object = component.create();
3277         QVERIFY(object != 0);
3278         CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3279         QVERIFY(crh != 0);
3280         crh->setDtorCount(&dtorCount);
3281         QMetaObject::invokeMethod(object, "createReference");
3282         CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3283         CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3284         QVERIFY(first != 0);
3285         QVERIFY(second != 0);
3286         first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3287         // now we have to reparent second and make second owned by JS.
3288         second->setParent(0);
3289         QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3290         QMetaObject::invokeMethod(object, "performGc");
3291         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3292         QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3293         delete object;
3294         hrmEngine.collectGarbage();
3295         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3296         QCOMPARE(dtorCount, 3);
3297     }
3298
3299     dtorCount = 0;
3300     {
3301         // Circular handle reference
3302         QDeclarativeEngine hrmEngine;
3303         QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3304         QObject *object = component.create();
3305         QVERIFY(object != 0);
3306         CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3307         QVERIFY(crh != 0);
3308         crh->setDtorCount(&dtorCount);
3309         QMetaObject::invokeMethod(object, "circularReference");
3310         CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3311         CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3312         QVERIFY(first != 0);
3313         QVERIFY(second != 0);
3314         first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3315         second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3316         // now we have to reparent and change ownership.
3317         first->setParent(0);
3318         second->setParent(0);
3319         QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3320         QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3321         QMetaObject::invokeMethod(object, "performGc");
3322         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3323         QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3324         delete object;
3325         hrmEngine.collectGarbage();
3326         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3327         QCOMPARE(dtorCount, 3);
3328     }
3329
3330     dtorCount = 0;
3331     {
3332         // multiple engine interaction - linear reference
3333         QDeclarativeEngine hrmEngine1;
3334         QDeclarativeEngine hrmEngine2;
3335         QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3336         QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3337         QObject *object1 = component1.create();
3338         QObject *object2 = component2.create();
3339         QVERIFY(object1 != 0);
3340         QVERIFY(object2 != 0);
3341         CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3342         CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3343         QVERIFY(crh1 != 0);
3344         QVERIFY(crh2 != 0);
3345         crh1->setDtorCount(&dtorCount);
3346         crh2->setDtorCount(&dtorCount);
3347         QMetaObject::invokeMethod(object1, "createReference");
3348         QMetaObject::invokeMethod(object2, "createReference");
3349         CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3350         CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3351         CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3352         CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3353         QVERIFY(first1 != 0);
3354         QVERIFY(second1 != 0);
3355         QVERIFY(first2 != 0);
3356         QVERIFY(second2 != 0);
3357         first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3358         // now we have to reparent second2 and make second2 owned by JS.
3359         second2->setParent(0);
3360         QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3361         QMetaObject::invokeMethod(object1, "performGc");
3362         QMetaObject::invokeMethod(object2, "performGc");
3363         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3364         QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3365         delete object1;
3366         delete object2;
3367         hrmEngine1.collectGarbage();
3368         hrmEngine2.collectGarbage();
3369         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3370         QCOMPARE(dtorCount, 6);
3371     }
3372
3373     dtorCount = 0;
3374     {
3375         // multiple engine interaction - circular reference
3376         QDeclarativeEngine hrmEngine1;
3377         QDeclarativeEngine hrmEngine2;
3378         QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3379         QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3380         QObject *object1 = component1.create();
3381         QObject *object2 = component2.create();
3382         QVERIFY(object1 != 0);
3383         QVERIFY(object2 != 0);
3384         CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3385         CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3386         QVERIFY(crh1 != 0);
3387         QVERIFY(crh2 != 0);
3388         crh1->setDtorCount(&dtorCount);
3389         crh2->setDtorCount(&dtorCount);
3390         QMetaObject::invokeMethod(object1, "createReference");
3391         QMetaObject::invokeMethod(object2, "createReference");
3392         CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3393         CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3394         CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3395         CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3396         QVERIFY(first1 != 0);
3397         QVERIFY(second1 != 0);
3398         QVERIFY(first2 != 0);
3399         QVERIFY(second2 != 0);
3400         first1->addReference(QDeclarativeData::get(second1)->v8object);  // create linear reference within engine1
3401         second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3402         second2->addReference(QDeclarativeData::get(first2)->v8object);  // create linear reference within engine2
3403         first2->addReference(QDeclarativeData::get(first1)->v8object);   // close the loop - circular ref across engines
3404         // now we have to reparent and change ownership to JS.
3405         first1->setParent(0);
3406         second1->setParent(0);
3407         first2->setParent(0);
3408         second2->setParent(0);
3409         QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3410         QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3411         QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3412         QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3413         QMetaObject::invokeMethod(object1, "performGc");
3414         QMetaObject::invokeMethod(object2, "performGc");
3415         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3416         QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3417         delete object1;
3418         delete object2;
3419         hrmEngine1.collectGarbage();
3420         hrmEngine2.collectGarbage();
3421         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3422         QCOMPARE(dtorCount, 6);
3423     }
3424
3425     dtorCount = 0;
3426     {
3427         // multiple engine interaction - linear reference with engine deletion
3428         QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3429         QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3430         QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3431         QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3432         QObject *object1 = component1.create();
3433         QObject *object2 = component2.create();
3434         QVERIFY(object1 != 0);
3435         QVERIFY(object2 != 0);
3436         CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3437         CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3438         QVERIFY(crh1 != 0);
3439         QVERIFY(crh2 != 0);
3440         crh1->setDtorCount(&dtorCount);
3441         crh2->setDtorCount(&dtorCount);
3442         QMetaObject::invokeMethod(object1, "createReference");
3443         QMetaObject::invokeMethod(object2, "createReference");
3444         CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3445         CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3446         CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3447         CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3448         QVERIFY(first1 != 0);
3449         QVERIFY(second1 != 0);
3450         QVERIFY(first2 != 0);
3451         QVERIFY(second2 != 0);
3452         first1->addReference(QDeclarativeData::get(second1)->v8object);  // create linear reference within engine1
3453         second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3454         second2->addReference(QDeclarativeData::get(first2)->v8object);  // create linear reference within engine2
3455         // now we have to reparent and change ownership to JS.
3456         first1->setParent(crh1);
3457         second1->setParent(0);
3458         first2->setParent(0);
3459         second2->setParent(0);
3460         QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3461         QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3462         QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3463         QMetaObject::invokeMethod(object1, "performGc");
3464         QMetaObject::invokeMethod(object2, "performGc");
3465         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3466         QCOMPARE(dtorCount, 0);
3467         delete hrmEngine2;
3468         QMetaObject::invokeMethod(object1, "performGc");
3469         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3470         QCOMPARE(dtorCount, 0);
3471         delete object1;
3472         delete object2;
3473         hrmEngine1->collectGarbage();
3474         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3475         QCOMPARE(dtorCount, 6);
3476         delete hrmEngine1;
3477     }
3478 }
3479
3480 // Test that assigning a null object works 
3481 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
3482 void tst_qdeclarativeecmascript::nullObjectBinding()
3483 {
3484     QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
3485
3486     QObject *object = component.create();
3487     QVERIFY(object != 0);
3488
3489     QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
3490
3491     delete object;
3492 }
3493
3494 // Test that bindings don't evaluate once the engine has been destroyed
3495 void tst_qdeclarativeecmascript::deletedEngine()
3496 {
3497     QDeclarativeEngine *engine = new QDeclarativeEngine;
3498     QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
3499
3500     QObject *object = component.create();
3501     QVERIFY(object != 0);
3502
3503     QCOMPARE(object->property("a").toInt(), 39);
3504     object->setProperty("b", QVariant(9));
3505     QCOMPARE(object->property("a").toInt(), 117);
3506
3507     delete engine;
3508
3509     QCOMPARE(object->property("a").toInt(), 117);
3510     object->setProperty("b", QVariant(10));
3511     QCOMPARE(object->property("a").toInt(), 117);
3512
3513     delete object;
3514 }
3515
3516 // Test the crashing part of QTBUG-9705
3517 void tst_qdeclarativeecmascript::libraryScriptAssert()
3518 {
3519     QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3520
3521     QObject *object = component.create();
3522     QVERIFY(object != 0);
3523
3524     delete object;
3525 }
3526
3527 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3528 {
3529     QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3530
3531     QObject *object = component.create();
3532     QVERIFY(object != 0);
3533
3534     QCOMPARE(object->property("test1").toInt(), 10);
3535     QCOMPARE(object->property("test2").toInt(), 11);
3536
3537     object->setProperty("runTest", true);
3538
3539     QCOMPARE(object->property("test1"), QVariant());
3540     QCOMPARE(object->property("test2"), QVariant());
3541
3542
3543     delete object;
3544 }
3545
3546 void tst_qdeclarativeecmascript::qtbug_9792()
3547 {
3548     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3549
3550     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3551
3552     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3553     QVERIFY(object != 0);
3554
3555     QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3556     object->basicSignal();
3557
3558     delete context;
3559
3560     transientErrorsMsgCount = 0;
3561     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3562
3563     object->basicSignal();
3564     
3565     qInstallMsgHandler(old);
3566
3567     QCOMPARE(transientErrorsMsgCount, 0);
3568
3569     delete object;
3570 }
3571
3572 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3573 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3574 {
3575     QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3576
3577     QObject *o = component.create();
3578     QVERIFY(o != 0);
3579
3580     QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3581     QVERIFY(nested != 0);
3582
3583     QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3584
3585     delete nested;
3586     nested = qvariant_cast<QObject *>(o->property("object"));
3587     QVERIFY(nested == 0);
3588
3589     // If the bug is present, the next line will crash
3590     delete o;
3591 }
3592
3593 // Test that we shut down without stupid warnings
3594 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3595 {
3596     {
3597     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3598
3599     QObject *o = component.create();
3600
3601     transientErrorsMsgCount = 0;
3602     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3603
3604     delete o;
3605
3606     qInstallMsgHandler(old);
3607
3608     QCOMPARE(transientErrorsMsgCount, 0);
3609     }
3610
3611
3612     {
3613     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3614
3615     QObject *o = component.create();
3616
3617     transientErrorsMsgCount = 0;
3618     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3619
3620     delete o;
3621
3622     qInstallMsgHandler(old);
3623
3624     QCOMPARE(transientErrorsMsgCount, 0);
3625     }
3626 }
3627
3628 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3629 {
3630     {
3631     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3632
3633     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3634     QVERIFY(o != 0);
3635
3636     QVERIFY(o->objectProperty() != 0);
3637
3638     o->setProperty("runTest", true);
3639
3640     QVERIFY(o->objectProperty() == 0);
3641
3642     delete o;
3643     }
3644
3645     {
3646     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3647
3648     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3649     QVERIFY(o != 0);
3650
3651     QVERIFY(o->objectProperty() == 0);
3652
3653     delete o;
3654     }
3655 }
3656
3657 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3658 {
3659     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3660
3661     QString url = component.url().toString();
3662     QString warning = url + ":4: Unable to assign a function to a property.";
3663     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3664     
3665     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3666     QVERIFY(o != 0);
3667
3668     QVERIFY(!o->property("a").isValid());
3669
3670     delete o;
3671 }
3672
3673 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3674 {
3675     QFETCH(QString, triggerProperty);
3676
3677     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3678     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3679
3680     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3681     QVERIFY(o != 0);
3682     QVERIFY(!o->property("a").isValid());
3683
3684     o->setProperty("aNumber", QVariant(5));
3685     o->setProperty(triggerProperty.toUtf8().constData(), true);
3686     QCOMPARE(o->property("a"), QVariant(50));
3687
3688     o->setProperty("aNumber", QVariant(10));
3689     QCOMPARE(o->property("a"), QVariant(100));
3690
3691     delete o;
3692 }
3693
3694 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3695 {
3696     QTest::addColumn<QString>("triggerProperty");
3697
3698     QTest::newRow("assign to property") << "assignToProperty";
3699     QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3700
3701     QTest::newRow("assign to value type") << "assignToValueType";
3702
3703     QTest::newRow("use 'this'") << "assignWithThis";
3704     QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3705 }
3706
3707 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3708 {
3709     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3710     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3711
3712     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3713     QVERIFY(o != 0);
3714     QVERIFY(!o->property("a").isValid());
3715
3716     o->setProperty("assignFuncWithoutReturn", true);
3717     QVERIFY(!o->property("a").isValid());
3718
3719     QString url = component.url().toString();
3720     QString warning = url + ":67: Unable to assign QString to int";
3721     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3722     o->setProperty("assignWrongType", true);
3723
3724     warning = url + ":71: Unable to assign QString to int";
3725     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3726     o->setProperty("assignWrongTypeToValueType", true);
3727
3728     delete o;
3729 }
3730
3731 void tst_qdeclarativeecmascript::eval()
3732 {
3733     QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3734
3735     QObject *o = component.create();
3736     QVERIFY(o != 0);
3737
3738     QCOMPARE(o->property("test1").toBool(), true);
3739     QCOMPARE(o->property("test2").toBool(), true);
3740     QCOMPARE(o->property("test3").toBool(), true);
3741     QCOMPARE(o->property("test4").toBool(), true);
3742     QCOMPARE(o->property("test5").toBool(), true);
3743
3744     delete o;
3745 }
3746
3747 void tst_qdeclarativeecmascript::function()
3748 {
3749     QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3750
3751     QObject *o = component.create();
3752     QVERIFY(o != 0);
3753
3754     QCOMPARE(o->property("test1").toBool(), true);
3755     QCOMPARE(o->property("test2").toBool(), true);
3756     QCOMPARE(o->property("test3").toBool(), true);
3757
3758     delete o;
3759 }
3760
3761 // Test the "Qt.include" method
3762 void tst_qdeclarativeecmascript::include()
3763 {
3764     // Non-library relative include
3765     {
3766     QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3767     QObject *o = component.create();
3768     QVERIFY(o != 0);
3769
3770     QCOMPARE(o->property("test0").toInt(), 99);
3771     QCOMPARE(o->property("test1").toBool(), true);
3772     QCOMPARE(o->property("test2").toBool(), true);
3773     QCOMPARE(o->property("test2_1").toBool(), true);
3774     QCOMPARE(o->property("test3").toBool(), true);
3775     QCOMPARE(o->property("test3_1").toBool(), true);
3776
3777     delete o;
3778     }
3779
3780     // Library relative include
3781     {
3782     QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3783     QObject *o = component.create();
3784     QVERIFY(o != 0);
3785
3786     QCOMPARE(o->property("test0").toInt(), 99);
3787     QCOMPARE(o->property("test1").toBool(), true);
3788     QCOMPARE(o->property("test2").toBool(), true);
3789     QCOMPARE(o->property("test2_1").toBool(), true);
3790     QCOMPARE(o->property("test3").toBool(), true);
3791     QCOMPARE(o->property("test3_1").toBool(), true);
3792
3793     delete o;
3794     }
3795
3796     // Callback
3797     {
3798     QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3799     QObject *o = component.create();
3800     QVERIFY(o != 0);
3801
3802     QCOMPARE(o->property("test1").toBool(), true);
3803     QCOMPARE(o->property("test2").toBool(), true);
3804     QCOMPARE(o->property("test3").toBool(), true);
3805     QCOMPARE(o->property("test4").toBool(), true);
3806     QCOMPARE(o->property("test5").toBool(), true);
3807     QCOMPARE(o->property("test6").toBool(), true);
3808
3809     delete o;
3810     }
3811
3812     // Including file with ".pragma library"
3813     {
3814     QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3815     QObject *o = component.create();
3816     QVERIFY(o != 0);
3817     QCOMPARE(o->property("test1").toInt(), 100);
3818
3819     delete o;
3820     }
3821
3822     // Remote - success
3823     {
3824     TestHTTPServer server(8111);
3825     QVERIFY(server.isValid());
3826     server.serveDirectory(SRCDIR "/data");
3827
3828     QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3829     QObject *o = component.create();
3830     QVERIFY(o != 0);
3831
3832     QTRY_VERIFY(o->property("done").toBool() == true);
3833     QTRY_VERIFY(o->property("done2").toBool() == true);
3834
3835     QCOMPARE(o->property("test1").toBool(), true);
3836     QCOMPARE(o->property("test2").toBool(), true);
3837     QCOMPARE(o->property("test3").toBool(), true);
3838     QCOMPARE(o->property("test4").toBool(), true);
3839     QCOMPARE(o->property("test5").toBool(), true);
3840
3841     QCOMPARE(o->property("test6").toBool(), true);
3842     QCOMPARE(o->property("test7").toBool(), true);
3843     QCOMPARE(o->property("test8").toBool(), true);
3844     QCOMPARE(o->property("test9").toBool(), true);
3845     QCOMPARE(o->property("test10").toBool(), true);
3846
3847     delete o;
3848     }
3849
3850     // Remote - error
3851     {
3852     TestHTTPServer server(8111);
3853     QVERIFY(server.isValid());
3854     server.serveDirectory(SRCDIR "/data");
3855
3856     QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3857     QObject *o = component.create();
3858     QVERIFY(o != 0);
3859
3860     QTRY_VERIFY(o->property("done").toBool() == true);
3861
3862     QCOMPARE(o->property("test1").toBool(), true);
3863     QCOMPARE(o->property("test2").toBool(), true);
3864     QCOMPARE(o->property("test3").toBool(), true);
3865
3866     delete o;
3867     }
3868 }
3869
3870 void tst_qdeclarativeecmascript::signalHandlers()
3871 {
3872     QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
3873     QObject *o = component.create();
3874     QVERIFY(o != 0);
3875
3876     QVERIFY(o->property("count").toInt() == 0);
3877     QMetaObject::invokeMethod(o, "testSignalCall");
3878     QCOMPARE(o->property("count").toInt(), 1);
3879
3880     QMetaObject::invokeMethod(o, "testSignalHandlerCall");
3881     QCOMPARE(o->property("count").toInt(), 1);
3882     QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
3883
3884     QVERIFY(o->property("funcCount").toInt() == 0);
3885     QMetaObject::invokeMethod(o, "testSignalConnection");
3886     QCOMPARE(o->property("funcCount").toInt(), 1);
3887
3888     QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
3889     QCOMPARE(o->property("funcCount").toInt(), 2);
3890
3891     QMetaObject::invokeMethod(o, "testSignalDefined");
3892     QCOMPARE(o->property("definedResult").toBool(), true);
3893
3894     QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
3895     QCOMPARE(o->property("definedHandlerResult").toBool(), true);
3896
3897     delete o;
3898 }
3899
3900 void tst_qdeclarativeecmascript::qtbug_10696()
3901 {
3902     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3903     QObject *o = component.create();
3904     QVERIFY(o != 0);
3905     delete o;
3906 }
3907
3908 void tst_qdeclarativeecmascript::qtbug_11606()
3909 {
3910     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3911     QObject *o = component.create();
3912     QVERIFY(o != 0);
3913     QCOMPARE(o->property("test").toBool(), true);
3914     delete o;
3915 }
3916
3917 void tst_qdeclarativeecmascript::qtbug_11600()
3918 {
3919     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3920     QObject *o = component.create();
3921     QVERIFY(o != 0);
3922     QCOMPARE(o->property("test").toBool(), true);
3923     delete o;
3924 }
3925
3926 // Reading and writing non-scriptable properties should fail
3927 void tst_qdeclarativeecmascript::nonscriptable()
3928 {
3929     QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3930     QObject *o = component.create();
3931     QVERIFY(o != 0);
3932     QCOMPARE(o->property("readOk").toBool(), true);
3933     QCOMPARE(o->property("writeOk").toBool(), true);
3934     delete o;
3935 }
3936
3937 // deleteLater() should not be callable from QML
3938 void tst_qdeclarativeecmascript::deleteLater()
3939 {
3940     QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3941     QObject *o = component.create();
3942     QVERIFY(o != 0);
3943     QCOMPARE(o->property("test").toBool(), true);
3944     delete o;
3945 }
3946
3947 void tst_qdeclarativeecmascript::in()
3948 {
3949     QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3950     QObject *o = component.create();
3951     QVERIFY(o != 0);
3952     QCOMPARE(o->property("test1").toBool(), true);
3953     QCOMPARE(o->property("test2").toBool(), true);
3954     delete o;
3955 }
3956
3957 void tst_qdeclarativeecmascript::sharedAttachedObject()
3958 {
3959     QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3960     QObject *o = component.create();
3961     QVERIFY(o != 0);
3962     QCOMPARE(o->property("test1").toBool(), true);
3963     QCOMPARE(o->property("test2").toBool(), true);
3964     delete o;
3965 }
3966
3967 // QTBUG-13999
3968 void tst_qdeclarativeecmascript::objectName()
3969 {
3970     QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3971     QObject *o = component.create();
3972     QVERIFY(o != 0);
3973
3974     QCOMPARE(o->property("test1").toString(), QString("hello"));
3975     QCOMPARE(o->property("test2").toString(), QString("ell"));
3976
3977     o->setObjectName("world");
3978
3979     QCOMPARE(o->property("test1").toString(), QString("world"));
3980     QCOMPARE(o->property("test2").toString(), QString("orl"));
3981
3982     delete o;
3983 }
3984
3985 void tst_qdeclarativeecmascript::writeRemovesBinding()
3986 {
3987     QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3988     QObject *o = component.create();
3989     QVERIFY(o != 0);
3990
3991     QCOMPARE(o->property("test").toBool(), true);
3992
3993     delete o;
3994 }
3995
3996 // Test bindings assigned to alias properties actually assign to the alias' target
3997 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3998 {
3999     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4000     QObject *o = component.create();
4001     QVERIFY(o != 0);
4002
4003     QCOMPARE(o->property("test").toBool(), true);
4004
4005     delete o;
4006 }
4007
4008 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4009 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4010 {
4011     { 
4012     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4013     QObject *o = component.create();
4014     QVERIFY(o != 0);
4015
4016     QCOMPARE(o->property("test").toBool(), true);
4017
4018     delete o;
4019     }
4020
4021     {
4022     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4023     QObject *o = component.create();
4024     QVERIFY(o != 0);
4025
4026     QCOMPARE(o->property("test").toBool(), true);
4027
4028     delete o;
4029     }
4030
4031     {
4032     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4033     QObject *o = component.create();
4034     QVERIFY(o != 0);
4035
4036     QCOMPARE(o->property("test").toBool(), true);
4037
4038     delete o;
4039     }
4040 }
4041
4042 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4043 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4044 {
4045     {
4046     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4047     QObject *o = component.create();
4048     QVERIFY(o != 0);
4049
4050     QCOMPARE(o->property("test").toBool(), true);
4051
4052     delete o;
4053     }
4054
4055     {
4056     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4057     QObject *o = component.create();
4058     QVERIFY(o != 0);
4059
4060     QCOMPARE(o->property("test").toBool(), true);
4061
4062     delete o;
4063     }
4064
4065     {
4066     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4067     QObject *o = component.create();
4068     QVERIFY(o != 0);
4069
4070     QCOMPARE(o->property("test").toBool(), true);
4071
4072     delete o;
4073     }
4074 }
4075
4076 // Allow an alais to a composite element
4077 // QTBUG-20200
4078 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4079 {
4080     QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4081
4082     QObject *object = component.create();
4083     QVERIFY(object != 0);
4084
4085     delete object;
4086 }
4087
4088 void tst_qdeclarativeecmascript::revisionErrors()
4089 {
4090     {
4091         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4092         QString url = component.url().toString();
4093
4094         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4095         QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4096         QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4097
4098         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4099         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4100         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4101         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4102         QVERIFY(object != 0);
4103         delete object;
4104     }
4105     {
4106         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4107         QString url = component.url().toString();
4108
4109         // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4110         // method2, prop2 from MyRevisionedClass not available
4111         // method4, prop4 from MyRevisionedSubclass not available
4112         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4113         QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4114         QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4115         QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4116         QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4117
4118         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4119         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4120         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4121         QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4122         QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4123         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4124         QVERIFY(object != 0);
4125         delete object;
4126     }
4127     {
4128         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4129         QString url = component.url().toString();
4130
4131         // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4132         // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4133         QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4134         QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4135         QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4136         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4137         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4138         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4139         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4140         QVERIFY(object != 0);
4141         delete object;
4142     }
4143 }
4144
4145 void tst_qdeclarativeecmascript::revision()
4146 {
4147     {
4148         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4149         QString url = component.url().toString();
4150
4151         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4152         QVERIFY(object != 0);
4153         delete object;
4154     }
4155     {
4156         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4157         QString url = component.url().toString();
4158
4159         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4160         QVERIFY(object != 0);
4161         delete object;
4162     }
4163     {
4164         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4165         QString url = component.url().toString();
4166
4167         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4168         QVERIFY(object != 0);
4169         delete object;
4170     }
4171     // Test that non-root classes can resolve revisioned methods
4172     {
4173         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4174
4175         QObject *object = component.create();
4176         QVERIFY(object != 0);
4177         QCOMPARE(object->property("test").toReal(), 11.);
4178         delete object;
4179     }
4180 }
4181
4182 void tst_qdeclarativeecmascript::realToInt()
4183 {
4184     QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
4185     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
4186     QVERIFY(object != 0);
4187
4188     QMetaObject::invokeMethod(object, "test1");
4189     QCOMPARE(object->value(), int(4));
4190     QMetaObject::invokeMethod(object, "test2");
4191     QCOMPARE(object->value(), int(8));
4192 }
4193 void tst_qdeclarativeecmascript::dynamicString()
4194 {
4195     QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
4196     QObject *object = component.create();
4197     QVERIFY(object != 0);
4198     QCOMPARE(object->property("stringProperty").toString(),
4199              QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
4200 }
4201
4202 QTEST_MAIN(tst_qdeclarativeecmascript)
4203
4204 #include "tst_qdeclarativeecmascript.moc"