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