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