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