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