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