Ensure that the prototype chain is checked in property Get
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativeecmascript / tst_qdeclarativeecmascript.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include "testtypes.h"
53 #include "testhttpserver.h"
54 #include "../../../shared/util.h"
55
56 #ifdef Q_OS_SYMBIAN
57 // In Symbian OS test data is located in applications private dir
58 #define SRCDIR "."
59 #endif
60
61 /*
62 This test covers evaluation of ECMAScript expressions and bindings from within
63 QML.  This does not include static QML language issues.
64
65 Static QML language issues are covered in qmllanguage
66 */
67 inline QUrl TEST_FILE(const QString &filename)
68 {
69     QFileInfo fileInfo(__FILE__);
70     return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
71 }
72
73 inline QUrl TEST_FILE(const char *filename)
74 {
75     return TEST_FILE(QLatin1String(filename));
76 }
77
78 class tst_qdeclarativeecmascript : public QObject
79 {
80     Q_OBJECT
81 public:
82     tst_qdeclarativeecmascript() {}
83
84 private slots:
85     void initTestCase();
86     void assignBasicTypes();
87     void idShortcutInvalidates();
88     void boolPropertiesEvaluateAsBool();
89     void methods();
90     void signalAssignment();
91     void bindingLoop();
92     void basicExpressions();
93     void basicExpressions_data();
94     void arrayExpressions();
95     void contextPropertiesTriggerReeval();
96     void objectPropertiesTriggerReeval();
97     void deferredProperties();
98     void deferredPropertiesErrors();
99     void extensionObjects();
100     void overrideExtensionProperties();
101     void attachedProperties();
102     void enums();
103     void valueTypeFunctions();
104     void constantsOverrideBindings();
105     void outerBindingOverridesInnerBinding();
106     void aliasPropertyAndBinding();
107     void nonExistentAttachedObject();
108     void scope();
109     void importScope();
110     void signalParameterTypes();
111     void objectsCompareAsEqual();
112     void dynamicCreation_data();
113     void dynamicCreation();
114     void dynamicDestruction();
115     void objectToString();
116     void objectHasOwnProperty();
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 that id.hasOwnProperty() works
1146 */
1147 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1148 {
1149     QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1150     QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1151     QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1152     QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1153
1154     QDeclarativeComponent component(&engine, url);
1155     QObject *object = component.create();
1156     QVERIFY(object != 0);
1157
1158     // test QObjects in QML
1159     QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1160     QVERIFY(object->property("result").value<bool>() == true);
1161     QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1162     QVERIFY(object->property("result").value<bool>() == false);
1163
1164     // now test other types in QML
1165     QObject *child = object->findChild<QObject*>("typeObj");
1166     QVERIFY(child != 0);
1167     QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1168     QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1169     QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1170     QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1171     QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1172     QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1173     QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1174     QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1175     QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1176     QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1177     QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1178     QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1179
1180     QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1181     QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1182     QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1183     QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1184     QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1185     QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1186     QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1187     QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1188     QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1189
1190     delete object;
1191 }
1192
1193 /*
1194 Tests bindings that indirectly cause their own deletion work.
1195
1196 This test is best run under valgrind to ensure no invalid memory access occur.
1197 */
1198 void tst_qdeclarativeecmascript::selfDeletingBinding()
1199 {
1200     {
1201         QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1202         QObject *object = component.create();
1203         QVERIFY(object != 0);
1204         object->setProperty("triggerDelete", true);
1205         delete object;
1206     }
1207
1208     {
1209         QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1210         QObject *object = component.create();
1211         QVERIFY(object != 0);
1212         object->setProperty("triggerDelete", true);
1213         delete object;
1214     }
1215 }
1216
1217 /*
1218 Test that extended object properties can be accessed.
1219
1220 This test a regression where this used to crash.  The issue was specificially
1221 for extended objects that did not include a synthesized meta object (so non-root
1222 and no synthesiszed properties).
1223 */
1224 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1225 {
1226     QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1227     QObject *object = component.create();
1228     QVERIFY(object != 0);
1229     delete object;
1230 }
1231
1232 /*
1233 Test file/lineNumbers for binding/Script errors.
1234 */
1235 void tst_qdeclarativeecmascript::scriptErrors()
1236 {
1237     QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1238     QString url = component.url().toString();
1239
1240     QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1241     QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1242     QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1243     QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1244     QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1245     QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1246     QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1247     QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1248
1249     QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1250     QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1251     QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1252     QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1253     QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1254     MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1255     QVERIFY(object != 0);
1256
1257     QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1258     emit object->basicSignal();
1259
1260     QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1261     emit object->anotherBasicSignal();
1262
1263     QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1264     emit object->thirdBasicSignal();
1265
1266     delete object;
1267 }
1268
1269 /*
1270 Test file/lineNumbers for inline functions.
1271 */
1272 void tst_qdeclarativeecmascript::functionErrors()
1273 {
1274     QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1275     QString url = component.url().toString();
1276
1277     QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1278
1279     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1280
1281     QObject *object = component.create();
1282     QVERIFY(object != 0);
1283     delete object;
1284
1285     // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1286     QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1287     url = componentTwo.url().toString();
1288     object = componentTwo.create();
1289     QVERIFY(object != 0);
1290
1291     QString srpname = object->property("srp_name").toString();
1292     
1293     warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname + 
1294               QLatin1String(" is not a function");
1295     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1296     QMetaObject::invokeMethod(object, "retrieveScarceResource");
1297     delete object;
1298 }
1299
1300 /*
1301 Test various errors that can occur when assigning a property from script
1302 */
1303 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1304 {
1305     QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1306
1307     QString url = component.url().toString();
1308
1309     QObject *object = component.create();
1310     QVERIFY(object != 0);
1311
1312     QCOMPARE(object->property("test1").toBool(), true);
1313     QCOMPARE(object->property("test2").toBool(), true);
1314
1315     delete object;
1316 }
1317     
1318 /*
1319 Test bindings still work when the reeval is triggered from within
1320 a signal script.
1321 */
1322 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1323 {
1324     QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1325     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1326     QVERIFY(object != 0);
1327
1328     QCOMPARE(object->property("base").toReal(), 50.);
1329     QCOMPARE(object->property("test1").toReal(), 50.);
1330     QCOMPARE(object->property("test2").toReal(), 50.);
1331
1332     object->basicSignal();
1333
1334     QCOMPARE(object->property("base").toReal(), 200.);
1335     QCOMPARE(object->property("test1").toReal(), 200.);
1336     QCOMPARE(object->property("test2").toReal(), 200.);
1337
1338     object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1339
1340     QCOMPARE(object->property("base").toReal(), 400.);
1341     QCOMPARE(object->property("test1").toReal(), 400.);
1342     QCOMPARE(object->property("test2").toReal(), 400.);
1343
1344     delete object;
1345 }
1346
1347 /*
1348 Test that list properties can be iterated from ECMAScript
1349 */
1350 void tst_qdeclarativeecmascript::listProperties()
1351 {
1352     QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1353     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1354     QVERIFY(object != 0);
1355
1356     QCOMPARE(object->property("test1").toInt(), 21);
1357     QCOMPARE(object->property("test2").toInt(), 2);
1358     QCOMPARE(object->property("test3").toBool(), true);
1359     QCOMPARE(object->property("test4").toBool(), true);
1360
1361     delete object;
1362 }
1363
1364 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1365 {
1366     QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1367     QString url = component.url().toString();
1368
1369     QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1370
1371     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1372     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1373     QVERIFY(object != 0);
1374
1375     QCOMPARE(object->property("test").toBool(), false);
1376
1377     MyQmlObject object2;
1378     MyQmlObject object3;
1379     object2.setObjectProperty(&object3);
1380     object->setObjectProperty(&object2);
1381
1382     QCOMPARE(object->property("test").toBool(), true);
1383
1384     delete object;
1385 }
1386
1387 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1388 {
1389     QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1390     QString url = component.url().toString();
1391
1392     QString warning = component.url().toString() + ":6: Error: JS exception";
1393
1394     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1395     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1396     QVERIFY(object != 0);
1397     delete object;
1398 }
1399
1400 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1401 {
1402     QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1403     QString url = component.url().toString();
1404
1405     QString warning = component.url().toString() + ":5: Error: JS exception";
1406
1407     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1408     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1409     QVERIFY(object != 0);
1410     delete object;
1411 }
1412
1413 static int transientErrorsMsgCount = 0;
1414 static void transientErrorsMsgHandler(QtMsgType, const char *)
1415 {
1416     ++transientErrorsMsgCount;
1417 }
1418
1419 // Check that transient binding errors are not displayed
1420 void tst_qdeclarativeecmascript::transientErrors()
1421 {
1422     {
1423     QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1424
1425     transientErrorsMsgCount = 0;
1426     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1427
1428     QObject *object = component.create();
1429     QVERIFY(object != 0);
1430
1431     qInstallMsgHandler(old);
1432
1433     QCOMPARE(transientErrorsMsgCount, 0);
1434
1435     delete object;
1436     }
1437
1438     // One binding erroring multiple times, but then resolving
1439     {
1440     QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1441
1442     transientErrorsMsgCount = 0;
1443     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1444
1445     QObject *object = component.create();
1446     QVERIFY(object != 0);
1447
1448     qInstallMsgHandler(old);
1449
1450     QCOMPARE(transientErrorsMsgCount, 0);
1451
1452     delete object;
1453     }
1454 }
1455
1456 // Check that errors during shutdown are minimized
1457 void tst_qdeclarativeecmascript::shutdownErrors()
1458 {
1459     QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1460     QObject *object = component.create();
1461     QVERIFY(object != 0);
1462
1463     transientErrorsMsgCount = 0;
1464     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1465
1466     delete object;
1467
1468     qInstallMsgHandler(old);
1469     QCOMPARE(transientErrorsMsgCount, 0);
1470 }
1471
1472 void tst_qdeclarativeecmascript::compositePropertyType()
1473 {
1474     QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1475     QTest::ignoreMessage(QtDebugMsg, "hello world");
1476     QObject *object = qobject_cast<QObject *>(component.create());
1477     delete object;
1478 }
1479
1480 // QTBUG-5759
1481 void tst_qdeclarativeecmascript::jsObject()
1482 {
1483     QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1484     QObject *object = component.create();
1485     QVERIFY(object != 0);
1486
1487     QCOMPARE(object->property("test").toInt(), 92);
1488
1489     delete object;
1490 }
1491
1492 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1493 {
1494     {
1495     QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1496     QObject *object = component.create();
1497     QVERIFY(object != 0);
1498
1499     QCOMPARE(object->property("resettableProperty").toInt(), 92);
1500
1501     object->setProperty("setUndefined", true);
1502
1503     QCOMPARE(object->property("resettableProperty").toInt(), 13);
1504
1505     object->setProperty("setUndefined", false);
1506
1507     QCOMPARE(object->property("resettableProperty").toInt(), 92);
1508
1509     delete object;
1510     }
1511     {
1512     QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1513     QObject *object = component.create();
1514     QVERIFY(object != 0);
1515
1516     QCOMPARE(object->property("resettableProperty").toInt(), 19);
1517
1518     QMetaObject::invokeMethod(object, "doReset");
1519
1520     QCOMPARE(object->property("resettableProperty").toInt(), 13);
1521
1522     delete object;
1523     }
1524 }
1525
1526 // QTBUG-6781
1527 void tst_qdeclarativeecmascript::bug1()
1528 {
1529     QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1530     QObject *object = component.create();
1531     QVERIFY(object != 0);
1532
1533     QCOMPARE(object->property("test").toInt(), 14);
1534
1535     object->setProperty("a", 11);
1536
1537     QCOMPARE(object->property("test").toInt(), 3);
1538
1539     object->setProperty("b", true);
1540
1541     QCOMPARE(object->property("test").toInt(), 9);
1542
1543     delete object;
1544 }
1545
1546 void tst_qdeclarativeecmascript::bug2()
1547 {
1548     QDeclarativeComponent component(&engine);
1549     component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1550
1551     QObject *object = component.create();
1552     QVERIFY(object != 0);
1553
1554     delete object;
1555 }
1556
1557 // Don't crash in createObject when the component has errors.
1558 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1559 {
1560     QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1561     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1562     QVERIFY(object != 0);
1563
1564     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1565     QMetaObject::invokeMethod(object, "dontCrash");
1566     QObject *created = object->objectProperty();
1567     QVERIFY(created == 0);
1568
1569     delete object;
1570 }
1571
1572 //QTBUG-9367
1573 void tst_qdeclarativeecmascript::regExpBug()
1574 {
1575     QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1576     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1577     QVERIFY(object != 0);
1578     QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1579     delete object;
1580 }
1581
1582 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1583 {
1584     QString functionSource = QLatin1String("(function(object) { return ") + 
1585                              QLatin1String(source) + QLatin1String(" })");
1586     v8::TryCatch tc;
1587     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1588     if (tc.HasCaught())
1589         return false;
1590     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1591     if (function.IsEmpty())
1592         return false;
1593     v8::Handle<v8::Value> args[] = { o };
1594     function->Call(engine->global(), 1, args);
1595     return tc.HasCaught();
1596 }
1597
1598 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o, 
1599                                   const char *source, v8::Handle<v8::Value> result)
1600 {
1601     QString functionSource = QLatin1String("(function(object) { return ") + 
1602                              QLatin1String(source) + QLatin1String(" })");
1603     v8::TryCatch tc;
1604     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1605     if (tc.HasCaught())
1606         return false;
1607     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1608     if (function.IsEmpty())
1609         return false;
1610     v8::Handle<v8::Value> args[] = { o };
1611
1612     v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1613
1614     if (tc.HasCaught())
1615         return false;
1616
1617     return value->StrictEquals(result);
1618 }
1619
1620 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o, 
1621                                              const char *source)
1622 {
1623     QString functionSource = QLatin1String("(function(object) { return ") + 
1624                              QLatin1String(source) + QLatin1String(" })");
1625     v8::TryCatch tc;
1626     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1627     if (tc.HasCaught())
1628         return v8::Handle<v8::Value>();
1629     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1630     if (function.IsEmpty())
1631         return v8::Handle<v8::Value>();
1632     v8::Handle<v8::Value> args[] = { o };
1633
1634     v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1635
1636     if (tc.HasCaught())
1637         return v8::Handle<v8::Value>();
1638     return value;
1639 }
1640
1641 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1642 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1643 #define EVALUATE(source) evaluate(engine, object, source)
1644
1645 void tst_qdeclarativeecmascript::callQtInvokables()
1646 {
1647     MyInvokableObject o;
1648
1649     QDeclarativeEngine qmlengine;
1650     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1651     
1652     QV8Engine *engine = ep->v8engine();
1653
1654     v8::HandleScope handle_scope;
1655     v8::Context::Scope scope(engine->context());
1656
1657     v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1658
1659     // Non-existent methods
1660     o.reset();
1661     QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1662     QCOMPARE(o.error(), false);
1663     QCOMPARE(o.invoked(), -1);
1664     QCOMPARE(o.actuals().count(), 0);
1665
1666     o.reset();
1667     QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1668     QCOMPARE(o.error(), false);
1669     QCOMPARE(o.invoked(), -1);
1670     QCOMPARE(o.actuals().count(), 0);
1671
1672     // Insufficient arguments
1673     o.reset();
1674     QVERIFY(EVALUATE_ERROR("object.method_int()"));
1675     QCOMPARE(o.error(), false);
1676     QCOMPARE(o.invoked(), -1);
1677     QCOMPARE(o.actuals().count(), 0);
1678
1679     o.reset();
1680     QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1681     QCOMPARE(o.error(), false);
1682     QCOMPARE(o.invoked(), -1);
1683     QCOMPARE(o.actuals().count(), 0);
1684
1685     // Excessive arguments
1686     o.reset();
1687     QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1688     QCOMPARE(o.error(), false);
1689     QCOMPARE(o.invoked(), 8);
1690     QCOMPARE(o.actuals().count(), 1);
1691     QCOMPARE(o.actuals().at(0), QVariant(10));
1692
1693     o.reset();
1694     QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1695     QCOMPARE(o.error(), false);
1696     QCOMPARE(o.invoked(), 9);
1697     QCOMPARE(o.actuals().count(), 2);
1698     QCOMPARE(o.actuals().at(0), QVariant(10));
1699     QCOMPARE(o.actuals().at(1), QVariant(11));
1700
1701     // Test return types
1702     o.reset();
1703     QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1704     QCOMPARE(o.error(), false);
1705     QCOMPARE(o.invoked(), 0);
1706     QCOMPARE(o.actuals().count(), 0);
1707
1708     o.reset();
1709     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1710     QCOMPARE(o.error(), false);
1711     QCOMPARE(o.invoked(), 1);
1712     QCOMPARE(o.actuals().count(), 0);
1713
1714     o.reset();
1715     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1716     QCOMPARE(o.error(), false);
1717     QCOMPARE(o.invoked(), 2);
1718     QCOMPARE(o.actuals().count(), 0);
1719
1720     o.reset();
1721     {
1722     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1723     QVERIFY(!ret.IsEmpty());
1724     QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1725     QCOMPARE(o.error(), false);
1726     QCOMPARE(o.invoked(), 3);
1727     QCOMPARE(o.actuals().count(), 0);
1728     }
1729
1730     o.reset();
1731     {
1732     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1733     QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1734     QCOMPARE(o.error(), false);
1735     QCOMPARE(o.invoked(), 4);
1736     QCOMPARE(o.actuals().count(), 0);
1737     }
1738
1739     o.reset();
1740     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1741     QCOMPARE(o.error(), false);
1742     QCOMPARE(o.invoked(), 5);
1743     QCOMPARE(o.actuals().count(), 0);
1744
1745     o.reset();
1746     {
1747     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1748     QVERIFY(ret->IsString());
1749     QCOMPARE(engine->toString(ret), QString("Hello world"));
1750     QCOMPARE(o.error(), false);
1751     QCOMPARE(o.invoked(), 6);
1752     QCOMPARE(o.actuals().count(), 0);
1753     }
1754
1755     o.reset();
1756     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1757     QCOMPARE(o.error(), false);
1758     QCOMPARE(o.invoked(), 7);
1759     QCOMPARE(o.actuals().count(), 0);
1760
1761     // Test arg types
1762     o.reset();
1763     QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1764     QCOMPARE(o.error(), false);
1765     QCOMPARE(o.invoked(), 8);
1766     QCOMPARE(o.actuals().count(), 1);
1767     QCOMPARE(o.actuals().at(0), QVariant(94));
1768
1769     o.reset();
1770     QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1771     QCOMPARE(o.error(), false);
1772     QCOMPARE(o.invoked(), 8);
1773     QCOMPARE(o.actuals().count(), 1);
1774     QCOMPARE(o.actuals().at(0), QVariant(94));
1775
1776     o.reset();
1777     QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1778     QCOMPARE(o.error(), false);
1779     QCOMPARE(o.invoked(), 8);
1780     QCOMPARE(o.actuals().count(), 1);
1781     QCOMPARE(o.actuals().at(0), QVariant(0));
1782
1783     o.reset();
1784     QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1785     QCOMPARE(o.error(), false);
1786     QCOMPARE(o.invoked(), 8);
1787     QCOMPARE(o.actuals().count(), 1);
1788     QCOMPARE(o.actuals().at(0), QVariant(0));
1789
1790     o.reset();
1791     QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1792     QCOMPARE(o.error(), false);
1793     QCOMPARE(o.invoked(), 8);
1794     QCOMPARE(o.actuals().count(), 1);
1795     QCOMPARE(o.actuals().at(0), QVariant(0));
1796
1797     o.reset();
1798     QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1799     QCOMPARE(o.error(), false);
1800     QCOMPARE(o.invoked(), 8);
1801     QCOMPARE(o.actuals().count(), 1);
1802     QCOMPARE(o.actuals().at(0), QVariant(0));
1803
1804     o.reset();
1805     QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1806     QCOMPARE(o.error(), false);
1807     QCOMPARE(o.invoked(), 9);
1808     QCOMPARE(o.actuals().count(), 2);
1809     QCOMPARE(o.actuals().at(0), QVariant(122));
1810     QCOMPARE(o.actuals().at(1), QVariant(9));
1811
1812     o.reset();
1813     QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1814     QCOMPARE(o.error(), false);
1815     QCOMPARE(o.invoked(), 10);
1816     QCOMPARE(o.actuals().count(), 1);
1817     QCOMPARE(o.actuals().at(0), QVariant(94.3));
1818
1819     o.reset();
1820     QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1821     QCOMPARE(o.error(), false);
1822     QCOMPARE(o.invoked(), 10);
1823     QCOMPARE(o.actuals().count(), 1);
1824     QCOMPARE(o.actuals().at(0), QVariant(94.3));
1825
1826     o.reset();
1827     QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1828     QCOMPARE(o.error(), false);
1829     QCOMPARE(o.invoked(), 10);
1830     QCOMPARE(o.actuals().count(), 1);
1831     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1832
1833     o.reset();
1834     QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1835     QCOMPARE(o.error(), false);
1836     QCOMPARE(o.invoked(), 10);
1837     QCOMPARE(o.actuals().count(), 1);
1838     QCOMPARE(o.actuals().at(0), QVariant(0));
1839
1840     o.reset();
1841     QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1842     QCOMPARE(o.error(), false);
1843     QCOMPARE(o.invoked(), 10);
1844     QCOMPARE(o.actuals().count(), 1);
1845     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1846
1847     o.reset();
1848     QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1849     QCOMPARE(o.error(), false);
1850     QCOMPARE(o.invoked(), 10);
1851     QCOMPARE(o.actuals().count(), 1);
1852     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1853
1854     o.reset();
1855     QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1856     QCOMPARE(o.error(), false);
1857     QCOMPARE(o.invoked(), 11);
1858     QCOMPARE(o.actuals().count(), 1);
1859     QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1860
1861     o.reset();
1862     QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1863     QCOMPARE(o.error(), false);
1864     QCOMPARE(o.invoked(), 11);
1865     QCOMPARE(o.actuals().count(), 1);
1866     QCOMPARE(o.actuals().at(0), QVariant("19"));
1867
1868     o.reset();
1869     {
1870     QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1871     QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1872     QCOMPARE(o.error(), false);
1873     QCOMPARE(o.invoked(), 11);
1874     QCOMPARE(o.actuals().count(), 1);
1875     QCOMPARE(o.actuals().at(0), QVariant(expected));
1876     }
1877
1878     o.reset();
1879     QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1880     QCOMPARE(o.error(), false);
1881     QCOMPARE(o.invoked(), 11);
1882     QCOMPARE(o.actuals().count(), 1);
1883     QCOMPARE(o.actuals().at(0), QVariant(QString()));
1884
1885     o.reset();
1886     QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1887     QCOMPARE(o.error(), false);
1888     QCOMPARE(o.invoked(), 11);
1889     QCOMPARE(o.actuals().count(), 1);
1890     QCOMPARE(o.actuals().at(0), QVariant(QString()));
1891
1892     o.reset();
1893     QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1894     QCOMPARE(o.error(), false);
1895     QCOMPARE(o.invoked(), 12);
1896     QCOMPARE(o.actuals().count(), 1);
1897     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1898
1899     o.reset();
1900     QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1901     QCOMPARE(o.error(), false);
1902     QCOMPARE(o.invoked(), 12);
1903     QCOMPARE(o.actuals().count(), 1);
1904     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1905
1906     o.reset();
1907     QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1908     QCOMPARE(o.error(), false);
1909     QCOMPARE(o.invoked(), 12);
1910     QCOMPARE(o.actuals().count(), 1);
1911     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1912
1913     o.reset();
1914     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
1915     QCOMPARE(o.error(), false);
1916     QCOMPARE(o.invoked(), 12);
1917     QCOMPARE(o.actuals().count(), 1);
1918     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1919
1920     o.reset();
1921     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
1922     QCOMPARE(o.error(), false);
1923     QCOMPARE(o.invoked(), 12);
1924     QCOMPARE(o.actuals().count(), 1);
1925     QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
1926
1927     o.reset();
1928     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
1929     QCOMPARE(o.error(), false);
1930     QCOMPARE(o.invoked(), 12);
1931     QCOMPARE(o.actuals().count(), 1);
1932     QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
1933
1934     o.reset();
1935     QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
1936     QCOMPARE(o.error(), false);
1937     QCOMPARE(o.invoked(), 13);
1938     QCOMPARE(o.actuals().count(), 1);
1939     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1940
1941     o.reset();
1942     QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
1943     QCOMPARE(o.error(), false);
1944     QCOMPARE(o.invoked(), 13);
1945     QCOMPARE(o.actuals().count(), 1);
1946     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1947
1948     o.reset();
1949     QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
1950     QCOMPARE(o.error(), false);
1951     QCOMPARE(o.invoked(), 13);
1952     QCOMPARE(o.actuals().count(), 1);
1953     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1954
1955     o.reset();
1956     QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
1957     QCOMPARE(o.error(), false);
1958     QCOMPARE(o.invoked(), 13);
1959     QCOMPARE(o.actuals().count(), 1);
1960     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1961
1962     o.reset();
1963     QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
1964     QCOMPARE(o.error(), false);
1965     QCOMPARE(o.invoked(), 13);
1966     QCOMPARE(o.actuals().count(), 1);
1967     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
1968
1969     o.reset();
1970     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
1971     QCOMPARE(o.error(), false);
1972     QCOMPARE(o.invoked(), 14);
1973     QCOMPARE(o.actuals().count(), 1);
1974     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
1975
1976     o.reset();
1977     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
1978     QCOMPARE(o.error(), false);
1979     QCOMPARE(o.invoked(), 14);
1980     QCOMPARE(o.actuals().count(), 1);
1981     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
1982
1983     o.reset();
1984     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
1985     QCOMPARE(o.error(), false);
1986     QCOMPARE(o.invoked(), 14);
1987     QCOMPARE(o.actuals().count(), 1);
1988     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
1989
1990     o.reset();
1991     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
1992     QCOMPARE(o.error(), false);
1993     QCOMPARE(o.invoked(), 14);
1994     QCOMPARE(o.actuals().count(), 1);
1995     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
1996
1997     o.reset();
1998     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
1999     QCOMPARE(o.error(), false);
2000     QCOMPARE(o.invoked(), 15);
2001     QCOMPARE(o.actuals().count(), 2);
2002     QCOMPARE(o.actuals().at(0), QVariant(4));
2003     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2004
2005     o.reset();
2006     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2007     QCOMPARE(o.error(), false);
2008     QCOMPARE(o.invoked(), 15);
2009     QCOMPARE(o.actuals().count(), 2);
2010     QCOMPARE(o.actuals().at(0), QVariant(8));
2011     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2012
2013     o.reset();
2014     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2015     QCOMPARE(o.error(), false);
2016     QCOMPARE(o.invoked(), 15);
2017     QCOMPARE(o.actuals().count(), 2);
2018     QCOMPARE(o.actuals().at(0), QVariant(3));
2019     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2020
2021     o.reset();
2022     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2023     QCOMPARE(o.error(), false);
2024     QCOMPARE(o.invoked(), 15);
2025     QCOMPARE(o.actuals().count(), 2);
2026     QCOMPARE(o.actuals().at(0), QVariant(44));
2027     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2028
2029     o.reset();
2030     QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2031     QCOMPARE(o.error(), false);
2032     QCOMPARE(o.invoked(), -1);
2033     QCOMPARE(o.actuals().count(), 0);
2034
2035     o.reset();
2036     QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2037     QCOMPARE(o.error(), false);
2038     QCOMPARE(o.invoked(), 16);
2039     QCOMPARE(o.actuals().count(), 1);
2040     QCOMPARE(o.actuals().at(0), QVariant(10));
2041
2042     o.reset();
2043     QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2044     QCOMPARE(o.error(), false);
2045     QCOMPARE(o.invoked(), 17);
2046     QCOMPARE(o.actuals().count(), 2);
2047     QCOMPARE(o.actuals().at(0), QVariant(10));
2048     QCOMPARE(o.actuals().at(1), QVariant(11));
2049
2050     o.reset();
2051     QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2052     QCOMPARE(o.error(), false);
2053     QCOMPARE(o.invoked(), 18);
2054     QCOMPARE(o.actuals().count(), 1);
2055     QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2056
2057     o.reset();
2058     QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2059     QCOMPARE(o.error(), false);
2060     QCOMPARE(o.invoked(), 19);
2061     QCOMPARE(o.actuals().count(), 1);
2062     QCOMPARE(o.actuals().at(0), QVariant(9));
2063
2064     o.reset();
2065     QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2066     QCOMPARE(o.error(), false);
2067     QCOMPARE(o.invoked(), 20);
2068     QCOMPARE(o.actuals().count(), 2);
2069     QCOMPARE(o.actuals().at(0), QVariant(10));
2070     QCOMPARE(o.actuals().at(1), QVariant(19));
2071
2072     o.reset();
2073     QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2074     QCOMPARE(o.error(), false);
2075     QCOMPARE(o.invoked(), 20);
2076     QCOMPARE(o.actuals().count(), 2);
2077     QCOMPARE(o.actuals().at(0), QVariant(10));
2078     QCOMPARE(o.actuals().at(1), QVariant(13));
2079
2080     o.reset();
2081     QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2082     QCOMPARE(o.error(), false);
2083     QCOMPARE(o.invoked(), -3);
2084     QCOMPARE(o.actuals().count(), 1);
2085     QCOMPARE(o.actuals().at(0), QVariant(9));
2086
2087     o.reset();
2088     QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2089     QCOMPARE(o.error(), false);
2090     QCOMPARE(o.invoked(), 21);
2091     QCOMPARE(o.actuals().count(), 2);
2092     QCOMPARE(o.actuals().at(0), QVariant(9));
2093     QCOMPARE(o.actuals().at(1), QVariant());
2094
2095     o.reset();
2096     QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2097     QCOMPARE(o.error(), false);
2098     QCOMPARE(o.invoked(), 21);
2099     QCOMPARE(o.actuals().count(), 2);
2100     QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2101     QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2102 }
2103
2104 // QTBUG-13047 (check that you can pass registered object types as args)
2105 void tst_qdeclarativeecmascript::invokableObjectArg()
2106 {
2107     QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2108
2109     QObject *o = component.create();
2110     QVERIFY(o);
2111     MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2112     QVERIFY(qmlobject);
2113     QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2114
2115     delete o;
2116 }
2117
2118 // QTBUG-13047 (check that you can return registered object types from methods)
2119 void tst_qdeclarativeecmascript::invokableObjectRet()
2120 {
2121     QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2122
2123     QObject *o = component.create();
2124     QVERIFY(o);
2125     QCOMPARE(o->property("test").toBool(), true);
2126     delete o;
2127 }
2128
2129 // QTBUG-5675
2130 void tst_qdeclarativeecmascript::listToVariant()
2131 {
2132     QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2133
2134     MyQmlContainer container;
2135
2136     QDeclarativeContext context(engine.rootContext());
2137     context.setContextObject(&container);
2138
2139     QObject *object = component.create(&context);
2140     QVERIFY(object != 0);
2141
2142     QVariant v = object->property("test");
2143     QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2144     QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2145
2146     delete object;
2147 }
2148
2149 // QTBUG-7957
2150 void tst_qdeclarativeecmascript::multiEngineObject()
2151 {
2152     MyQmlObject obj;
2153     obj.setStringProperty("Howdy planet");
2154
2155     QDeclarativeEngine e1;
2156     e1.rootContext()->setContextProperty("thing", &obj);
2157     QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2158
2159     QDeclarativeEngine e2;
2160     e2.rootContext()->setContextProperty("thing", &obj);
2161     QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2162
2163     QObject *o1 = c1.create();
2164     QObject *o2 = c2.create();
2165
2166     QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2167     QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2168
2169     delete o2;
2170     delete o1;
2171 }
2172
2173 // Test that references to QObjects are cleanup when the object is destroyed
2174 void tst_qdeclarativeecmascript::deletedObject()
2175 {
2176     QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2177
2178     QObject *object = component.create();
2179
2180     QCOMPARE(object->property("test1").toBool(), true);
2181     QCOMPARE(object->property("test2").toBool(), true);
2182     QCOMPARE(object->property("test3").toBool(), true);
2183     QCOMPARE(object->property("test4").toBool(), true);
2184
2185     delete object;
2186 }
2187
2188 void tst_qdeclarativeecmascript::attachedPropertyScope()
2189 {
2190     QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2191
2192     QObject *object = component.create();
2193     QVERIFY(object != 0);
2194
2195     MyQmlAttachedObject *attached = 
2196         qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2197     QVERIFY(attached != 0);
2198
2199     QCOMPARE(object->property("value2").toInt(), 0);
2200
2201     attached->emitMySignal();
2202
2203     QCOMPARE(object->property("value2").toInt(), 9);
2204
2205     delete object;
2206 }
2207
2208 void tst_qdeclarativeecmascript::scriptConnect()
2209 {
2210     {
2211         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2212
2213         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2214         QVERIFY(object != 0);
2215
2216         QCOMPARE(object->property("test").toBool(), false);
2217         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2218         QCOMPARE(object->property("test").toBool(), true);
2219
2220         delete object;
2221     }
2222
2223     {
2224         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2225
2226         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2227         QVERIFY(object != 0);
2228
2229         QCOMPARE(object->property("test").toBool(), false);
2230         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2231         QCOMPARE(object->property("test").toBool(), true);
2232
2233         delete object;
2234     }
2235
2236     {
2237         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2238
2239         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2240         QVERIFY(object != 0);
2241
2242         QCOMPARE(object->property("test").toBool(), false);
2243         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2244         QCOMPARE(object->property("test").toBool(), true);
2245
2246         delete object;
2247     }
2248
2249     {
2250         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2251
2252         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2253         QVERIFY(object != 0);
2254
2255         QCOMPARE(object->methodCalled(), false);
2256         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2257         QCOMPARE(object->methodCalled(), true);
2258
2259         delete object;
2260     }
2261
2262     {
2263         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2264
2265         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2266         QVERIFY(object != 0);
2267
2268         QCOMPARE(object->methodCalled(), false);
2269         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2270         QCOMPARE(object->methodCalled(), true);
2271
2272         delete object;
2273     }
2274
2275     {
2276         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2277
2278         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2279         QVERIFY(object != 0);
2280
2281         QCOMPARE(object->property("test").toInt(), 0);
2282         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2283         QCOMPARE(object->property("test").toInt(), 2);
2284
2285         delete object;
2286     }
2287 }
2288
2289 void tst_qdeclarativeecmascript::scriptDisconnect()
2290 {
2291     {
2292         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2293
2294         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2295         QVERIFY(object != 0);
2296
2297         QCOMPARE(object->property("test").toInt(), 0);
2298         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2299         QCOMPARE(object->property("test").toInt(), 1);
2300         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2301         QCOMPARE(object->property("test").toInt(), 2);
2302         emit object->basicSignal();
2303         QCOMPARE(object->property("test").toInt(), 2);
2304         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2305         QCOMPARE(object->property("test").toInt(), 2);
2306
2307         delete object;
2308     }
2309
2310     {
2311         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2312
2313         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2314         QVERIFY(object != 0);
2315
2316         QCOMPARE(object->property("test").toInt(), 0);
2317         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2318         QCOMPARE(object->property("test").toInt(), 1);
2319         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2320         QCOMPARE(object->property("test").toInt(), 2);
2321         emit object->basicSignal();
2322         QCOMPARE(object->property("test").toInt(), 2);
2323         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2324         QCOMPARE(object->property("test").toInt(), 2);
2325
2326         delete object;
2327     }
2328
2329     {
2330         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2331
2332         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2333         QVERIFY(object != 0);
2334
2335         QCOMPARE(object->property("test").toInt(), 0);
2336         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2337         QCOMPARE(object->property("test").toInt(), 1);
2338         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2339         QCOMPARE(object->property("test").toInt(), 2);
2340         emit object->basicSignal();
2341         QCOMPARE(object->property("test").toInt(), 2);
2342         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2343         QCOMPARE(object->property("test").toInt(), 3);
2344
2345         delete object;
2346     }
2347     {
2348         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2349
2350         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2351         QVERIFY(object != 0);
2352
2353         QCOMPARE(object->property("test").toInt(), 0);
2354         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2355         QCOMPARE(object->property("test").toInt(), 1);
2356         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2357         QCOMPARE(object->property("test").toInt(), 2);
2358         emit object->basicSignal();
2359         QCOMPARE(object->property("test").toInt(), 2);
2360         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2361         QCOMPARE(object->property("test").toInt(), 3);
2362
2363         delete object;
2364     }
2365 }
2366
2367 class OwnershipObject : public QObject
2368 {
2369     Q_OBJECT
2370 public:
2371     OwnershipObject() { object = new QObject; }
2372
2373     QPointer<QObject> object;
2374
2375 public slots:
2376     QObject *getObject() { return object; }
2377 };
2378
2379 void tst_qdeclarativeecmascript::ownership()
2380 {
2381     OwnershipObject own;
2382     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2383     context->setContextObject(&own);
2384
2385     {
2386         QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2387
2388         QVERIFY(own.object != 0);
2389
2390         QObject *object = component.create(context);
2391
2392         engine.collectGarbage();
2393
2394         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2395
2396         QVERIFY(own.object == 0);
2397
2398         delete object;
2399     }
2400
2401     own.object = new QObject(&own);
2402
2403     {
2404         QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2405
2406         QVERIFY(own.object != 0);
2407
2408         QObject *object = component.create(context);
2409         
2410         engine.collectGarbage();
2411
2412         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2413
2414         QVERIFY(own.object != 0);
2415
2416         delete object;
2417     }
2418
2419     delete context;
2420 }
2421
2422 class CppOwnershipReturnValue : public QObject
2423 {
2424     Q_OBJECT
2425 public:
2426     CppOwnershipReturnValue() : value(0) {}
2427     ~CppOwnershipReturnValue() { delete value; }
2428
2429     Q_INVOKABLE QObject *create() {
2430         value = new QObject;
2431         QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2432         return value;
2433     }
2434
2435     Q_INVOKABLE MyQmlObject *createQmlObject() {
2436         MyQmlObject *rv = new MyQmlObject;
2437         value = rv;
2438         return rv;
2439     }
2440
2441     QPointer<QObject> value;
2442 };
2443
2444 // QTBUG-15695.  
2445 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2446 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2447 {
2448     CppOwnershipReturnValue source;
2449
2450     {
2451     QDeclarativeEngine engine;
2452     engine.rootContext()->setContextProperty("source", &source);
2453
2454     QVERIFY(source.value == 0);
2455
2456     QDeclarativeComponent component(&engine);
2457     component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2458
2459     QObject *object = component.create();
2460
2461     QVERIFY(object != 0);
2462     QVERIFY(source.value != 0);
2463
2464     delete object;
2465     }
2466
2467     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2468
2469     QVERIFY(source.value != 0);
2470 }
2471
2472 // QTBUG-15697
2473 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2474 {
2475     CppOwnershipReturnValue source;
2476
2477     {
2478     QDeclarativeEngine engine;
2479     engine.rootContext()->setContextProperty("source", &source);
2480
2481     QVERIFY(source.value == 0);
2482
2483     QDeclarativeComponent component(&engine);
2484     component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2485
2486     QObject *object = component.create();
2487
2488     QVERIFY(object != 0);
2489     QVERIFY(source.value != 0);
2490
2491     delete object;
2492     }
2493
2494     engine.collectGarbage();
2495     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2496
2497     QVERIFY(source.value == 0);
2498 }
2499
2500 class QListQObjectMethodsObject : public QObject
2501 {
2502     Q_OBJECT
2503 public:
2504     QListQObjectMethodsObject() {
2505         m_objects.append(new MyQmlObject());
2506         m_objects.append(new MyQmlObject());
2507     }
2508
2509     ~QListQObjectMethodsObject() {
2510         qDeleteAll(m_objects);
2511     }
2512
2513 public slots:
2514     QList<QObject *> getObjects() { return m_objects; }
2515
2516 private:
2517     QList<QObject *> m_objects;
2518 };
2519
2520 // Tests that returning a QList<QObject*> from a method works
2521 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2522 {
2523     QListQObjectMethodsObject obj;
2524     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2525     context->setContextObject(&obj);
2526
2527     QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2528
2529     QObject *object = component.create(context);
2530
2531     QCOMPARE(object->property("test").toInt(), 2);
2532     QCOMPARE(object->property("test2").toBool(), true);
2533
2534     delete object;
2535     delete context;
2536 }
2537
2538 // QTBUG-9205
2539 void tst_qdeclarativeecmascript::strictlyEquals()
2540 {
2541     QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2542
2543     QObject *object = component.create();
2544     QVERIFY(object != 0);
2545
2546     QCOMPARE(object->property("test1").toBool(), true);
2547     QCOMPARE(object->property("test2").toBool(), true);
2548     QCOMPARE(object->property("test3").toBool(), true);
2549     QCOMPARE(object->property("test4").toBool(), true);
2550     QCOMPARE(object->property("test5").toBool(), true);
2551     QCOMPARE(object->property("test6").toBool(), true);
2552     QCOMPARE(object->property("test7").toBool(), true);
2553     QCOMPARE(object->property("test8").toBool(), true);
2554
2555     delete object;
2556 }
2557
2558 void tst_qdeclarativeecmascript::compiled()
2559 {
2560     QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2561
2562     QObject *object = component.create();
2563     QVERIFY(object != 0);
2564
2565     QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2566     QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2567     QCOMPARE(object->property("test3").toBool(), true);
2568     QCOMPARE(object->property("test4").toBool(), false);
2569     QCOMPARE(object->property("test5").toBool(), false);
2570     QCOMPARE(object->property("test6").toBool(), true);
2571
2572     QCOMPARE(object->property("test7").toInt(), 185);
2573     QCOMPARE(object->property("test8").toInt(), 167);
2574     QCOMPARE(object->property("test9").toBool(), true);
2575     QCOMPARE(object->property("test10").toBool(), false);
2576     QCOMPARE(object->property("test11").toBool(), false);
2577     QCOMPARE(object->property("test12").toBool(), true);
2578
2579     QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2580     QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2581     QCOMPARE(object->property("test15").toBool(), false);
2582     QCOMPARE(object->property("test16").toBool(), true);
2583
2584     QCOMPARE(object->property("test17").toInt(), 5);
2585     QCOMPARE(object->property("test18").toReal(), qreal(176));
2586     QCOMPARE(object->property("test19").toInt(), 7);
2587     QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2588     QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2589     QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2590     QCOMPARE(object->property("test23").toBool(), true);
2591     QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2592     QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2593
2594     delete object;
2595 }
2596
2597 // Test that numbers assigned in bindings as strings work consistently
2598 void tst_qdeclarativeecmascript::numberAssignment()
2599 {
2600     QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2601
2602     QObject *object = component.create();
2603     QVERIFY(object != 0);
2604
2605     QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2606     QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2607     QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2608     QCOMPARE(object->property("test3"), QVariant((qreal)6));
2609     QCOMPARE(object->property("test4"), QVariant((qreal)6));
2610
2611     QCOMPARE(object->property("test5"), QVariant((int)7));
2612     QCOMPARE(object->property("test6"), QVariant((int)7));
2613     QCOMPARE(object->property("test7"), QVariant((int)6));
2614     QCOMPARE(object->property("test8"), QVariant((int)6));
2615
2616     QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2617     QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2618     QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2619     QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2620
2621     delete object;
2622 }
2623
2624 void tst_qdeclarativeecmascript::propertySplicing()
2625 {
2626     QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2627
2628     QObject *object = component.create();
2629     QVERIFY(object != 0);
2630
2631     QCOMPARE(object->property("test").toBool(), true);
2632
2633     delete object;
2634 }
2635
2636 // QTBUG-16683
2637 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2638 {
2639     QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2640
2641     MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2642     QVERIFY(object != 0);
2643
2644     MyQmlObject::MyType type;
2645     type.value = 0x8971123;
2646     emit object->signalWithUnknownType(type);
2647
2648     MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2649
2650     QCOMPARE(result.value, type.value);
2651
2652
2653     delete object;
2654 }
2655
2656 void tst_qdeclarativeecmascript::moduleApi()
2657 {
2658     QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
2659     QObject *object = component.create();
2660     QVERIFY(object != 0);
2661     QCOMPARE(object->property("existingUriTest").toInt(), 20);
2662
2663     QEXPECT_FAIL("", "QTBUG-17318", Continue);
2664     QCOMPARE(object->property("scriptTest").toInt(), 13);
2665     QCOMPARE(object->property("qobjectTest").toInt(), 20);
2666     QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
2667     QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
2668     QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
2669     QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
2670     delete object;
2671
2672     // test that caching of module apis works correctly.
2673     QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
2674     object = componentTwo.create();
2675     QVERIFY(object != 0);
2676     QCOMPARE(object->property("existingUriTest").toInt(), 20);
2677     QEXPECT_FAIL("", "QTBUG-17318", Continue);
2678     QCOMPARE(object->property("scriptTest").toInt(), 13);            // shouldn't have incremented.
2679     QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);   // shouldn't have incremented.
2680     delete object;
2681
2682     // test that writing to a property of module apis works correctly.
2683     QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
2684     QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
2685     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2686     object = componentThree.create();
2687     QVERIFY(object != 0);
2688     QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2689     QCOMPARE(object->property("writableProperty").toInt(), 50);
2690     QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
2691     QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
2692     QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2693     QCOMPARE(object->property("writableProperty").toInt(), 30);
2694     delete object;
2695
2696     QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
2697     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2698     object = failOne.create();
2699     QVERIFY(object == 0); // should have failed: invalid major version
2700
2701     QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
2702     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2703     object = failTwo.create();
2704     QVERIFY(object == 0); // should have failed: invalid minor version
2705 }
2706
2707 void tst_qdeclarativeecmascript::importScripts()
2708 {
2709     QObject *object = 0;
2710
2711     // first, ensure that the required behaviour works.
2712     QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2713     object = component.create();
2714     QVERIFY(object != 0);
2715     QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2716     QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2717     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2718     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2719     delete object;
2720
2721     QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2722     object = componentTwo.create();
2723     QVERIFY(object != 0);
2724     QCOMPARE(object->property("componentError"), QVariant(5));
2725     delete object;
2726
2727     // then, ensure that unintended behaviour does not work.
2728     QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2729     QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2730     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2731     object = failOneComponent.create();
2732     QVERIFY(object != 0);
2733     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2734     delete object;
2735     QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2736     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2737     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2738     object = failTwoComponent.create();
2739     QVERIFY(object != 0);
2740     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2741     delete object;
2742     QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2743     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2744     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2745     object = failThreeComponent.create();
2746     QVERIFY(object != 0);
2747     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2748     delete object;
2749     QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2750     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2751     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2752     object = failFourComponent.create();
2753     QVERIFY(object != 0);
2754     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2755     delete object;
2756     QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2757     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2758     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2759     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2760     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2761     object = failFiveComponent.create();
2762     QVERIFY(object != 0);
2763     QCOMPARE(object->property("componentError"), QVariant(0));
2764     delete object;
2765
2766     // also, test that importing scripts with .pragma library works as required
2767     QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2768     object = pragmaLibraryComponent.create();
2769     QVERIFY(object != 0);
2770     QCOMPARE(object->property("testValue"), QVariant(31));
2771     delete object;
2772
2773     // and that .pragma library scripts don't inherit imports from any .qml file
2774     QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2775     object = pragmaLibraryComponentTwo.create();
2776     QVERIFY(object != 0);
2777     QCOMPARE(object->property("testValue"), QVariant(0));
2778     delete object;
2779 }
2780
2781 void tst_qdeclarativeecmascript::scarceResources()
2782 {
2783     QPixmap origPixmap(100, 100);
2784     origPixmap.fill(Qt::blue);
2785
2786     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2787     ScarceResourceObject *eo = 0;
2788     QObject *object = 0;
2789
2790     // in the following three cases, the instance created from the component
2791     // has a property which is a copy of the scarce resource; hence, the
2792     // resource should NOT be detached prior to deletion of the object instance,
2793     // unless the resource is destroyed explicitly.
2794     QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2795     object = component.create();
2796     QVERIFY(object != 0);
2797     QVERIFY(object->property("scarceResourceCopy").isValid());
2798     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2799     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2800     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2801     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2802     delete object;
2803
2804     QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2805     object = componentTwo.create();
2806     QVERIFY(object != 0);
2807     QVERIFY(object->property("scarceResourceCopy").isValid());
2808     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2809     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2810     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2811     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2812     delete object;
2813
2814     QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
2815     object = componentThree.create();
2816     QVERIFY(object != 0);
2817     QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
2818     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2819     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2820     QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
2821     delete object;
2822
2823     // in the following three cases, no other copy should exist in memory,
2824     // and so it should be detached (unless explicitly preserved).
2825     QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
2826     object = componentFour.create();
2827     QVERIFY(object != 0);
2828     QVERIFY(object->property("scarceResourceTest").isValid());
2829     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2830     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2831     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2832     QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
2833     delete object;
2834
2835     QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
2836     object = componentFive.create();
2837     QVERIFY(object != 0);
2838     QVERIFY(object->property("scarceResourceTest").isValid());
2839     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2840     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2841     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2842     QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
2843     delete object;
2844
2845     QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
2846     object = componentSix.create();
2847     QVERIFY(object != 0);
2848     QVERIFY(object->property("scarceResourceTest").isValid());
2849     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2850     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2851     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2852     QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
2853     delete object;
2854
2855     // test that scarce resources are handled correctly for imports
2856     QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
2857     object = componentSeven.create();
2858     QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
2859     QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
2860     delete object;
2861
2862     QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
2863     object = componentEight.create();
2864     QVERIFY(object != 0);
2865     QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
2866     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2867     delete object;
2868
2869     QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
2870     object = componentNine.create();
2871     QVERIFY(object != 0);
2872     QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
2873     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2874     QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
2875     QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
2876     QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
2877     QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
2878     delete object;
2879
2880     // test that scarce resources are handled properly in signal invocation
2881     QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
2882     object = componentTen.create();
2883     QVERIFY(object != 0);
2884     QObject *srsc = object->findChild<QObject*>("srsc");
2885     QVERIFY(srsc);
2886     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
2887     QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
2888     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2889     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2890     QMetaObject::invokeMethod(srsc, "testSignal");
2891     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
2892     QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
2893     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2894     QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
2895     QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
2896     QVERIFY(srsc->property("scarceResourceCopy").isValid());
2897     QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2898     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2899     QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
2900     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2901     delete object;
2902
2903     // test that scarce resources are handled properly from js functions in qml files
2904     QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
2905     object = componentEleven.create();
2906     QVERIFY(object != 0);
2907     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2908     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2909     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2910     QMetaObject::invokeMethod(object, "retrieveScarceResource");
2911     QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
2912     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2913     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2914     QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
2915     QMetaObject::invokeMethod(object, "releaseScarceResource");
2916     QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
2917     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2918     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2919     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2920     delete object;
2921
2922     // test that if an exception occurs while invoking js function from cpp, that the resources are released.
2923     QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
2924     object = componentTwelve.create();
2925     QVERIFY(object != 0);
2926     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2927     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2928     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2929     QString srp_name = object->property("srp_name").toString();
2930     QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
2931     QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
2932     QMetaObject::invokeMethod(object, "retrieveScarceResource");
2933     QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
2934     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2935     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2936     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2937     delete object;
2938 }
2939
2940 void tst_qdeclarativeecmascript::propertyChangeSlots()
2941 {
2942     // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
2943     QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
2944     QObject *object = component.create();
2945     QVERIFY(object != 0);
2946     delete object;
2947
2948     // ensure that invalid property names fail properly.
2949     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2950     QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
2951     QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
2952     QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
2953     object = e1.create();
2954     QVERIFY(object == 0);
2955     delete object;
2956
2957     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2958     QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
2959     expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
2960     QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
2961     object = e2.create();
2962     QVERIFY(object == 0);
2963     delete object;
2964
2965     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2966     QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
2967     expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
2968     QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
2969     object = e3.create();
2970     QVERIFY(object == 0);
2971     delete object;
2972
2973     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2974     QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
2975     expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
2976     QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
2977     object = e4.create();
2978     QVERIFY(object == 0);
2979     delete object;
2980 }
2981
2982 // Ensure that QObject type conversion works on binding assignment
2983 void tst_qdeclarativeecmascript::elementAssign()
2984 {
2985     QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
2986
2987     QObject *object = component.create();
2988     QVERIFY(object != 0);
2989
2990     QCOMPARE(object->property("test").toBool(), true);
2991
2992     delete object;
2993 }
2994
2995 // QTBUG-12457
2996 void tst_qdeclarativeecmascript::objectPassThroughSignals()
2997 {
2998     QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
2999
3000     QObject *object = component.create();
3001     QVERIFY(object != 0);
3002
3003     QCOMPARE(object->property("test").toBool(), true);
3004
3005     delete object;
3006 }
3007
3008 // QTBUG-20242
3009 void tst_qdeclarativeecmascript::booleanConversion()
3010 {
3011     QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3012
3013     QObject *object = component.create();
3014     QVERIFY(object != 0);
3015
3016     QCOMPARE(object->property("test_true1").toBool(), true);
3017     QCOMPARE(object->property("test_true2").toBool(), true);
3018     QCOMPARE(object->property("test_true3").toBool(), true);
3019     QCOMPARE(object->property("test_true4").toBool(), true);
3020     QCOMPARE(object->property("test_true5").toBool(), true);
3021
3022     QCOMPARE(object->property("test_false1").toBool(), false);
3023     QCOMPARE(object->property("test_false2").toBool(), false);
3024     QCOMPARE(object->property("test_false3").toBool(), false);
3025
3026     delete object;
3027 }
3028
3029 // Test that assigning a null object works 
3030 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
3031 void tst_qdeclarativeecmascript::nullObjectBinding()
3032 {
3033     QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
3034
3035     QObject *object = component.create();
3036     QVERIFY(object != 0);
3037
3038     QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
3039
3040     delete object;
3041 }
3042
3043 // Test that bindings don't evaluate once the engine has been destroyed
3044 void tst_qdeclarativeecmascript::deletedEngine()
3045 {
3046     QDeclarativeEngine *engine = new QDeclarativeEngine;
3047     QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
3048
3049     QObject *object = component.create();
3050     QVERIFY(object != 0);
3051
3052     QCOMPARE(object->property("a").toInt(), 39);
3053     object->setProperty("b", QVariant(9));
3054     QCOMPARE(object->property("a").toInt(), 117);
3055
3056     delete engine;
3057
3058     QCOMPARE(object->property("a").toInt(), 117);
3059     object->setProperty("b", QVariant(10));
3060     QCOMPARE(object->property("a").toInt(), 117);
3061
3062     delete object;
3063 }
3064
3065 // Test the crashing part of QTBUG-9705
3066 void tst_qdeclarativeecmascript::libraryScriptAssert()
3067 {
3068     QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3069
3070     QObject *object = component.create();
3071     QVERIFY(object != 0);
3072
3073     delete object;
3074 }
3075
3076 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3077 {
3078     QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3079
3080     QObject *object = component.create();
3081     QVERIFY(object != 0);
3082
3083     QCOMPARE(object->property("test1").toInt(), 10);
3084     QCOMPARE(object->property("test2").toInt(), 11);
3085
3086     object->setProperty("runTest", true);
3087
3088     QCOMPARE(object->property("test1"), QVariant());
3089     QCOMPARE(object->property("test2"), QVariant());
3090
3091
3092     delete object;
3093 }
3094
3095 void tst_qdeclarativeecmascript::qtbug_9792()
3096 {
3097     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3098
3099     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3100
3101     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3102     QVERIFY(object != 0);
3103
3104     QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3105     object->basicSignal();
3106
3107     delete context;
3108
3109     transientErrorsMsgCount = 0;
3110     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3111
3112     object->basicSignal();
3113     
3114     qInstallMsgHandler(old);
3115
3116     QCOMPARE(transientErrorsMsgCount, 0);
3117
3118     delete object;
3119 }
3120
3121 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3122 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3123 {
3124     QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3125
3126     QObject *o = component.create();
3127     QVERIFY(o != 0);
3128
3129     QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3130     QVERIFY(nested != 0);
3131
3132     QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3133
3134     delete nested;
3135     nested = qvariant_cast<QObject *>(o->property("object"));
3136     QVERIFY(nested == 0);
3137
3138     // If the bug is present, the next line will crash
3139     delete o;
3140 }
3141
3142 // Test that we shut down without stupid warnings
3143 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3144 {
3145     {
3146     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3147
3148     QObject *o = component.create();
3149
3150     transientErrorsMsgCount = 0;
3151     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3152
3153     delete o;
3154
3155     qInstallMsgHandler(old);
3156
3157     QCOMPARE(transientErrorsMsgCount, 0);
3158     }
3159
3160
3161     {
3162     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3163
3164     QObject *o = component.create();
3165
3166     transientErrorsMsgCount = 0;
3167     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3168
3169     delete o;
3170
3171     qInstallMsgHandler(old);
3172
3173     QCOMPARE(transientErrorsMsgCount, 0);
3174     }
3175 }
3176
3177 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3178 {
3179     {
3180     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3181
3182     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3183     QVERIFY(o != 0);
3184
3185     QVERIFY(o->objectProperty() != 0);
3186
3187     o->setProperty("runTest", true);
3188
3189     QVERIFY(o->objectProperty() == 0);
3190
3191     delete o;
3192     }
3193
3194     {
3195     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3196
3197     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3198     QVERIFY(o != 0);
3199
3200     QVERIFY(o->objectProperty() == 0);
3201
3202     delete o;
3203     }
3204 }
3205
3206 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3207 {
3208     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3209
3210     QString url = component.url().toString();
3211     QString warning = url + ":4: Unable to assign a function to a property.";
3212     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3213     
3214     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3215     QVERIFY(o != 0);
3216
3217     QVERIFY(!o->property("a").isValid());
3218
3219     delete o;
3220 }
3221
3222 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3223 {
3224     QFETCH(QString, triggerProperty);
3225
3226     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3227     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3228
3229     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3230     QVERIFY(o != 0);
3231     QVERIFY(!o->property("a").isValid());
3232
3233     o->setProperty("aNumber", QVariant(5));
3234     o->setProperty(triggerProperty.toUtf8().constData(), true);
3235     QCOMPARE(o->property("a"), QVariant(50));
3236
3237     o->setProperty("aNumber", QVariant(10));
3238     QCOMPARE(o->property("a"), QVariant(100));
3239
3240     delete o;
3241 }
3242
3243 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3244 {
3245     QTest::addColumn<QString>("triggerProperty");
3246
3247     QTest::newRow("assign to property") << "assignToProperty";
3248     QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3249
3250     QTest::newRow("assign to value type") << "assignToValueType";
3251
3252     QTest::newRow("use 'this'") << "assignWithThis";
3253     QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3254 }
3255
3256 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3257 {
3258     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3259     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3260
3261     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3262     QVERIFY(o != 0);
3263     QVERIFY(!o->property("a").isValid());
3264
3265     o->setProperty("assignFuncWithoutReturn", true);
3266     QVERIFY(!o->property("a").isValid());
3267
3268     QString url = component.url().toString();
3269     QString warning = url + ":67: Unable to assign QString to int";
3270     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3271     o->setProperty("assignWrongType", true);
3272
3273     warning = url + ":71: Unable to assign QString to int";
3274     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3275     o->setProperty("assignWrongTypeToValueType", true);
3276
3277     delete o;
3278 }
3279
3280 void tst_qdeclarativeecmascript::eval()
3281 {
3282     QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3283
3284     QObject *o = component.create();
3285     QVERIFY(o != 0);
3286
3287     QCOMPARE(o->property("test1").toBool(), true);
3288     QCOMPARE(o->property("test2").toBool(), true);
3289     QCOMPARE(o->property("test3").toBool(), true);
3290     QCOMPARE(o->property("test4").toBool(), true);
3291     QCOMPARE(o->property("test5").toBool(), true);
3292
3293     delete o;
3294 }
3295
3296 void tst_qdeclarativeecmascript::function()
3297 {
3298     QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3299
3300     QObject *o = component.create();
3301     QVERIFY(o != 0);
3302
3303     QCOMPARE(o->property("test1").toBool(), true);
3304     QCOMPARE(o->property("test2").toBool(), true);
3305     QCOMPARE(o->property("test3").toBool(), true);
3306
3307     delete o;
3308 }
3309
3310 // Test the "Qt.include" method
3311 void tst_qdeclarativeecmascript::include()
3312 {
3313     // Non-library relative include
3314     {
3315     QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3316     QObject *o = component.create();
3317     QVERIFY(o != 0);
3318
3319     QCOMPARE(o->property("test0").toInt(), 99);
3320     QCOMPARE(o->property("test1").toBool(), true);
3321     QCOMPARE(o->property("test2").toBool(), true);
3322     QCOMPARE(o->property("test2_1").toBool(), true);
3323     QCOMPARE(o->property("test3").toBool(), true);
3324     QCOMPARE(o->property("test3_1").toBool(), true);
3325
3326     delete o;
3327     }
3328
3329     // Library relative include
3330     {
3331     QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3332     QObject *o = component.create();
3333     QVERIFY(o != 0);
3334
3335     QCOMPARE(o->property("test0").toInt(), 99);
3336     QCOMPARE(o->property("test1").toBool(), true);
3337     QCOMPARE(o->property("test2").toBool(), true);
3338     QCOMPARE(o->property("test2_1").toBool(), true);
3339     QCOMPARE(o->property("test3").toBool(), true);
3340     QCOMPARE(o->property("test3_1").toBool(), true);
3341
3342     delete o;
3343     }
3344
3345     // Callback
3346     {
3347     QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3348     QObject *o = component.create();
3349     QVERIFY(o != 0);
3350
3351     QCOMPARE(o->property("test1").toBool(), true);
3352     QCOMPARE(o->property("test2").toBool(), true);
3353     QCOMPARE(o->property("test3").toBool(), true);
3354     QCOMPARE(o->property("test4").toBool(), true);
3355     QCOMPARE(o->property("test5").toBool(), true);
3356     QCOMPARE(o->property("test6").toBool(), true);
3357
3358     delete o;
3359     }
3360
3361     // Including file with ".pragma library"
3362     {
3363     QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3364     QObject *o = component.create();
3365     QVERIFY(o != 0);
3366     QCOMPARE(o->property("test1").toInt(), 100);
3367
3368     delete o;
3369     }
3370
3371     // Remote - success
3372     {
3373     TestHTTPServer server(8111);
3374     QVERIFY(server.isValid());
3375     server.serveDirectory(SRCDIR "/data");
3376
3377     QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3378     QObject *o = component.create();
3379     QVERIFY(o != 0);
3380
3381     QTRY_VERIFY(o->property("done").toBool() == true);
3382     QTRY_VERIFY(o->property("done2").toBool() == true);
3383
3384     QCOMPARE(o->property("test1").toBool(), true);
3385     QCOMPARE(o->property("test2").toBool(), true);
3386     QCOMPARE(o->property("test3").toBool(), true);
3387     QCOMPARE(o->property("test4").toBool(), true);
3388     QCOMPARE(o->property("test5").toBool(), true);
3389
3390     QCOMPARE(o->property("test6").toBool(), true);
3391     QCOMPARE(o->property("test7").toBool(), true);
3392     QCOMPARE(o->property("test8").toBool(), true);
3393     QCOMPARE(o->property("test9").toBool(), true);
3394     QCOMPARE(o->property("test10").toBool(), true);
3395
3396     delete o;
3397     }
3398
3399     // Remote - error
3400     {
3401     TestHTTPServer server(8111);
3402     QVERIFY(server.isValid());
3403     server.serveDirectory(SRCDIR "/data");
3404
3405     QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3406     QObject *o = component.create();
3407     QVERIFY(o != 0);
3408
3409     QTRY_VERIFY(o->property("done").toBool() == true);
3410
3411     QCOMPARE(o->property("test1").toBool(), true);
3412     QCOMPARE(o->property("test2").toBool(), true);
3413     QCOMPARE(o->property("test3").toBool(), true);
3414
3415     delete o;
3416     }
3417 }
3418
3419 void tst_qdeclarativeecmascript::qtbug_10696()
3420 {
3421     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3422     QObject *o = component.create();
3423     QVERIFY(o != 0);
3424     delete o;
3425 }
3426
3427 void tst_qdeclarativeecmascript::qtbug_11606()
3428 {
3429     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3430     QObject *o = component.create();
3431     QVERIFY(o != 0);
3432     QCOMPARE(o->property("test").toBool(), true);
3433     delete o;
3434 }
3435
3436 void tst_qdeclarativeecmascript::qtbug_11600()
3437 {
3438     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3439     QObject *o = component.create();
3440     QVERIFY(o != 0);
3441     QCOMPARE(o->property("test").toBool(), true);
3442     delete o;
3443 }
3444
3445 // Reading and writing non-scriptable properties should fail
3446 void tst_qdeclarativeecmascript::nonscriptable()
3447 {
3448     QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3449     QObject *o = component.create();
3450     QVERIFY(o != 0);
3451     QCOMPARE(o->property("readOk").toBool(), true);
3452     QCOMPARE(o->property("writeOk").toBool(), true);
3453     delete o;
3454 }
3455
3456 // deleteLater() should not be callable from QML
3457 void tst_qdeclarativeecmascript::deleteLater()
3458 {
3459     QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3460     QObject *o = component.create();
3461     QVERIFY(o != 0);
3462     QCOMPARE(o->property("test").toBool(), true);
3463     delete o;
3464 }
3465
3466 void tst_qdeclarativeecmascript::in()
3467 {
3468     QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3469     QObject *o = component.create();
3470     QVERIFY(o != 0);
3471     QCOMPARE(o->property("test1").toBool(), true);
3472     QCOMPARE(o->property("test2").toBool(), true);
3473     delete o;
3474 }
3475
3476 void tst_qdeclarativeecmascript::sharedAttachedObject()
3477 {
3478     QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3479     QObject *o = component.create();
3480     QVERIFY(o != 0);
3481     QCOMPARE(o->property("test1").toBool(), true);
3482     QCOMPARE(o->property("test2").toBool(), true);
3483     delete o;
3484 }
3485
3486 // QTBUG-13999
3487 void tst_qdeclarativeecmascript::objectName()
3488 {
3489     QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3490     QObject *o = component.create();
3491     QVERIFY(o != 0);
3492
3493     QCOMPARE(o->property("test1").toString(), QString("hello"));
3494     QCOMPARE(o->property("test2").toString(), QString("ell"));
3495
3496     o->setObjectName("world");
3497
3498     QCOMPARE(o->property("test1").toString(), QString("world"));
3499     QCOMPARE(o->property("test2").toString(), QString("orl"));
3500
3501     delete o;
3502 }
3503
3504 void tst_qdeclarativeecmascript::writeRemovesBinding()
3505 {
3506     QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3507     QObject *o = component.create();
3508     QVERIFY(o != 0);
3509
3510     QCOMPARE(o->property("test").toBool(), true);
3511
3512     delete o;
3513 }
3514
3515 // Test bindings assigned to alias properties actually assign to the alias' target
3516 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3517 {
3518     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3519     QObject *o = component.create();
3520     QVERIFY(o != 0);
3521
3522     QCOMPARE(o->property("test").toBool(), true);
3523
3524     delete o;
3525 }
3526
3527 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3528 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3529 {
3530     { 
3531     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3532     QObject *o = component.create();
3533     QVERIFY(o != 0);
3534
3535     QCOMPARE(o->property("test").toBool(), true);
3536
3537     delete o;
3538     }
3539
3540     {
3541     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
3542     QObject *o = component.create();
3543     QVERIFY(o != 0);
3544
3545     QCOMPARE(o->property("test").toBool(), true);
3546
3547     delete o;
3548     }
3549
3550     {
3551     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
3552     QObject *o = component.create();
3553     QVERIFY(o != 0);
3554
3555     QCOMPARE(o->property("test").toBool(), true);
3556
3557     delete o;
3558     }
3559 }
3560
3561 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
3562 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
3563 {
3564     {
3565     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
3566     QObject *o = component.create();
3567     QVERIFY(o != 0);
3568
3569     QCOMPARE(o->property("test").toBool(), true);
3570
3571     delete o;
3572     }
3573
3574     {
3575     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
3576     QObject *o = component.create();
3577     QVERIFY(o != 0);
3578
3579     QCOMPARE(o->property("test").toBool(), true);
3580
3581     delete o;
3582     }
3583
3584     {
3585     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
3586     QObject *o = component.create();
3587     QVERIFY(o != 0);
3588
3589     QCOMPARE(o->property("test").toBool(), true);
3590
3591     delete o;
3592     }
3593 }
3594
3595 // Allow an alais to a composite element
3596 // QTBUG-20200
3597 void tst_qdeclarativeecmascript::aliasToCompositeElement()
3598 {
3599     QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
3600
3601     QObject *object = component.create();
3602     QVERIFY(object != 0);
3603
3604     delete object;
3605 }
3606
3607 void tst_qdeclarativeecmascript::revisionErrors()
3608 {
3609     {
3610         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
3611         QString url = component.url().toString();
3612
3613         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3614         QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
3615         QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
3616
3617         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3618         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3619         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3620         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3621         QVERIFY(object != 0);
3622         delete object;
3623     }
3624     {
3625         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
3626         QString url = component.url().toString();
3627
3628         // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
3629         // method2, prop2 from MyRevisionedClass not available
3630         // method4, prop4 from MyRevisionedSubclass not available
3631         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3632         QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
3633         QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
3634         QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
3635         QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
3636
3637         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3638         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3639         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3640         QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
3641         QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
3642         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3643         QVERIFY(object != 0);
3644         delete object;
3645     }
3646     {
3647         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
3648         QString url = component.url().toString();
3649
3650         // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
3651         // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
3652         QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
3653         QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
3654         QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
3655         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3656         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3657         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3658         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3659         QVERIFY(object != 0);
3660         delete object;
3661     }
3662 }
3663
3664 void tst_qdeclarativeecmascript::revision()
3665 {
3666     {
3667         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
3668         QString url = component.url().toString();
3669
3670         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3671         QVERIFY(object != 0);
3672         delete object;
3673     }
3674     {
3675         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
3676         QString url = component.url().toString();
3677
3678         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3679         QVERIFY(object != 0);
3680         delete object;
3681     }
3682     {
3683         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
3684         QString url = component.url().toString();
3685
3686         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3687         QVERIFY(object != 0);
3688         delete object;
3689     }
3690     // Test that non-root classes can resolve revisioned methods
3691     {
3692         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
3693
3694         QObject *object = component.create();
3695         QVERIFY(object != 0);
3696         QCOMPARE(object->property("test").toReal(), 11.);
3697         delete object;
3698     }
3699 }
3700
3701 void tst_qdeclarativeecmascript::realToInt()
3702 {
3703     QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
3704     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
3705     QVERIFY(object != 0);
3706
3707     QMetaObject::invokeMethod(object, "test1");
3708     QCOMPARE(object->value(), int(4));
3709     QMetaObject::invokeMethod(object, "test2");
3710     QCOMPARE(object->value(), int(8));
3711 }
3712 void tst_qdeclarativeecmascript::dynamicString()
3713 {
3714     QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
3715     QObject *object = component.create();
3716     QVERIFY(object != 0);
3717     QCOMPARE(object->property("stringProperty").toString(),
3718              QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
3719 }
3720
3721 QTEST_MAIN(tst_qdeclarativeecmascript)
3722
3723 #include "tst_qdeclarativeecmascript.moc"