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