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