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