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