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