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