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