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