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