Initial V8 integration
[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/qscriptdeclarativeclass_p.h>
53 #include "testtypes.h"
54 #include "testhttpserver.h"
55 #include "../../../shared/util.h"
56
57 #ifdef Q_OS_SYMBIAN
58 // In Symbian OS test data is located in applications private dir
59 #define SRCDIR "."
60 #endif
61
62 /*
63 This test covers evaluation of ECMAScript expressions and bindings from within
64 QML.  This does not include static QML language issues.
65
66 Static QML language issues are covered in qmllanguage
67 */
68 inline QUrl TEST_FILE(const QString &filename)
69 {
70     QFileInfo fileInfo(__FILE__);
71     return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
72 }
73
74 inline QUrl TEST_FILE(const char *filename)
75 {
76     return TEST_FILE(QLatin1String(filename));
77 }
78
79 class tst_qdeclarativeecmascript : public QObject
80 {
81     Q_OBJECT
82 public:
83     tst_qdeclarativeecmascript() {}
84
85 private slots:
86     void initTestCase();
87     void assignBasicTypes();
88     void idShortcutInvalidates();
89     void boolPropertiesEvaluateAsBool();
90     void methods();
91     void signalAssignment();
92     void bindingLoop();
93     void basicExpressions();
94     void basicExpressions_data();
95     void arrayExpressions();
96     void contextPropertiesTriggerReeval();
97     void objectPropertiesTriggerReeval();
98     void deferredProperties();
99     void deferredPropertiesErrors();
100     void extensionObjects();
101     void overrideExtensionProperties();
102     void attachedProperties();
103     void enums();
104     void valueTypeFunctions();
105     void constantsOverrideBindings();
106     void outerBindingOverridesInnerBinding();
107     void aliasPropertyAndBinding();
108     void nonExistentAttachedObject();
109     void scope();
110     void signalParameterTypes();
111     void objectsCompareAsEqual();
112     void dynamicCreation_data();
113     void dynamicCreation();
114     void dynamicDestruction();
115     void objectToString();
116     void selfDeletingBinding();
117     void extendedObjectPropertyLookup();
118     void scriptErrors();
119     void functionErrors();
120     void propertyAssignmentErrors();
121     void signalTriggeredBindings();
122     void listProperties();
123     void exceptionClearsOnReeval();
124     void exceptionSlotProducesWarning();
125     void exceptionBindingProducesWarning();
126     void transientErrors();
127     void shutdownErrors();
128     void compositePropertyType();
129     void jsObject();
130     void undefinedResetsProperty();
131     void listToVariant();
132     void multiEngineObject();
133     void deletedObject();
134     void attachedPropertyScope();
135     void scriptConnect();
136     void scriptDisconnect();
137     void ownership();
138     void cppOwnershipReturnValue();
139     void ownershipCustomReturnValue();
140     void qlistqobjectMethods();
141     void strictlyEquals();
142     void compiled();
143     void numberAssignment();
144     void propertySplicing();
145     void signalWithUnknownTypes();
146     void moduleApi();
147     void importScripts();
148     void scarceResources();
149     void propertyChangeSlots();
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
1202     QString srpname = object->property("srp_name").toString();
1203     
1204     warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname + 
1205               QLatin1String(" is not a function");
1206     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1207     QMetaObject::invokeMethod(object, "retrieveScarceResource");
1208     delete object;
1209 }
1210
1211 /*
1212 Test various errors that can occur when assigning a property from script
1213 */
1214 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1215 {
1216     QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1217
1218     QString url = component.url().toString();
1219
1220     QObject *object = component.create();
1221     QVERIFY(object != 0);
1222
1223     QCOMPARE(object->property("test1").toBool(), true);
1224     QCOMPARE(object->property("test2").toBool(), true);
1225
1226     delete object;
1227 }
1228     
1229 /*
1230 Test bindings still work when the reeval is triggered from within
1231 a signal script.
1232 */
1233 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1234 {
1235     QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1236     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1237     QVERIFY(object != 0);
1238
1239     QCOMPARE(object->property("base").toReal(), 50.);
1240     QCOMPARE(object->property("test1").toReal(), 50.);
1241     QCOMPARE(object->property("test2").toReal(), 50.);
1242
1243     object->basicSignal();
1244
1245     QCOMPARE(object->property("base").toReal(), 200.);
1246     QCOMPARE(object->property("test1").toReal(), 200.);
1247     QCOMPARE(object->property("test2").toReal(), 200.);
1248
1249     object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1250
1251     QCOMPARE(object->property("base").toReal(), 400.);
1252     QCOMPARE(object->property("test1").toReal(), 400.);
1253     QCOMPARE(object->property("test2").toReal(), 400.);
1254
1255     delete object;
1256 }
1257
1258 /*
1259 Test that list properties can be iterated from ECMAScript
1260 */
1261 void tst_qdeclarativeecmascript::listProperties()
1262 {
1263     QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1264     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1265     QVERIFY(object != 0);
1266
1267     QCOMPARE(object->property("test1").toInt(), 21);
1268     QCOMPARE(object->property("test2").toInt(), 2);
1269     QCOMPARE(object->property("test3").toBool(), true);
1270     QCOMPARE(object->property("test4").toBool(), true);
1271
1272     delete object;
1273 }
1274
1275 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1276 {
1277     QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1278     QString url = component.url().toString();
1279
1280     QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1281
1282     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1283     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1284     QVERIFY(object != 0);
1285
1286     QCOMPARE(object->property("test").toBool(), false);
1287
1288     MyQmlObject object2;
1289     MyQmlObject object3;
1290     object2.setObjectProperty(&object3);
1291     object->setObjectProperty(&object2);
1292
1293     QCOMPARE(object->property("test").toBool(), true);
1294
1295     delete object;
1296 }
1297
1298 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1299 {
1300     QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1301     QString url = component.url().toString();
1302
1303     QString warning = component.url().toString() + ":6: Error: JS exception";
1304
1305     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1306     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1307     QVERIFY(object != 0);
1308     delete object;
1309 }
1310
1311 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1312 {
1313     QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1314     QString url = component.url().toString();
1315
1316     QString warning = component.url().toString() + ":5: Error: JS exception";
1317
1318     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1319     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1320     QVERIFY(object != 0);
1321     delete object;
1322 }
1323
1324 static int transientErrorsMsgCount = 0;
1325 static void transientErrorsMsgHandler(QtMsgType, const char *)
1326 {
1327     ++transientErrorsMsgCount;
1328 }
1329
1330 // Check that transient binding errors are not displayed
1331 void tst_qdeclarativeecmascript::transientErrors()
1332 {
1333     {
1334     QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1335
1336     transientErrorsMsgCount = 0;
1337     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1338
1339     QObject *object = component.create();
1340     QVERIFY(object != 0);
1341
1342     qInstallMsgHandler(old);
1343
1344     QCOMPARE(transientErrorsMsgCount, 0);
1345
1346     delete object;
1347     }
1348
1349     // One binding erroring multiple times, but then resolving
1350     {
1351     QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1352
1353     transientErrorsMsgCount = 0;
1354     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1355
1356     QObject *object = component.create();
1357     QVERIFY(object != 0);
1358
1359     qInstallMsgHandler(old);
1360
1361     QCOMPARE(transientErrorsMsgCount, 0);
1362
1363     delete object;
1364     }
1365 }
1366
1367 // Check that errors during shutdown are minimized
1368 void tst_qdeclarativeecmascript::shutdownErrors()
1369 {
1370     QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1371     QObject *object = component.create();
1372     QVERIFY(object != 0);
1373
1374     transientErrorsMsgCount = 0;
1375     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1376
1377     delete object;
1378
1379     qInstallMsgHandler(old);
1380     QCOMPARE(transientErrorsMsgCount, 0);
1381 }
1382
1383 void tst_qdeclarativeecmascript::compositePropertyType()
1384 {
1385     QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1386     QTest::ignoreMessage(QtDebugMsg, "hello world");
1387     QObject *object = qobject_cast<QObject *>(component.create());
1388     delete object;
1389 }
1390
1391 // QTBUG-5759
1392 void tst_qdeclarativeecmascript::jsObject()
1393 {
1394     QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1395     QObject *object = component.create();
1396     QVERIFY(object != 0);
1397
1398     QCOMPARE(object->property("test").toInt(), 92);
1399
1400     delete object;
1401 }
1402
1403 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1404 {
1405     {
1406     QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1407     QObject *object = component.create();
1408     QVERIFY(object != 0);
1409
1410     QCOMPARE(object->property("resettableProperty").toInt(), 92);
1411
1412     object->setProperty("setUndefined", true);
1413
1414     QCOMPARE(object->property("resettableProperty").toInt(), 13);
1415
1416     object->setProperty("setUndefined", false);
1417
1418     QCOMPARE(object->property("resettableProperty").toInt(), 92);
1419
1420     delete object;
1421     }
1422     {
1423     QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1424     QObject *object = component.create();
1425     QVERIFY(object != 0);
1426
1427     QCOMPARE(object->property("resettableProperty").toInt(), 19);
1428
1429     QMetaObject::invokeMethod(object, "doReset");
1430
1431     QCOMPARE(object->property("resettableProperty").toInt(), 13);
1432
1433     delete object;
1434     }
1435 }
1436
1437 // QTBUG-6781
1438 void tst_qdeclarativeecmascript::bug1()
1439 {
1440     QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1441     QObject *object = component.create();
1442     QVERIFY(object != 0);
1443
1444     QCOMPARE(object->property("test").toInt(), 14);
1445
1446     object->setProperty("a", 11);
1447
1448     QCOMPARE(object->property("test").toInt(), 3);
1449
1450     object->setProperty("b", true);
1451
1452     QCOMPARE(object->property("test").toInt(), 9);
1453
1454     delete object;
1455 }
1456
1457 void tst_qdeclarativeecmascript::bug2()
1458 {
1459     QDeclarativeComponent component(&engine);
1460     component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1461
1462     QObject *object = component.create();
1463     QVERIFY(object != 0);
1464
1465     delete object;
1466 }
1467
1468 // Don't crash in createObject when the component has errors.
1469 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1470 {
1471     QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1472     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1473     QVERIFY(object != 0);
1474
1475     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1476     QMetaObject::invokeMethod(object, "dontCrash");
1477     QObject *created = object->objectProperty();
1478     QVERIFY(created == 0);
1479
1480     delete object;
1481 }
1482
1483 //QTBUG-9367
1484 void tst_qdeclarativeecmascript::regExpBug()
1485 {
1486     QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1487     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1488     QVERIFY(object != 0);
1489     QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1490     delete object;
1491 }
1492
1493 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1494 {
1495     QString functionSource = QLatin1String("(function(object) { return ") + 
1496                              QLatin1String(source) + QLatin1String(" })");
1497     v8::TryCatch tc;
1498     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1499     if (tc.HasCaught())
1500         return false;
1501     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1502     if (function.IsEmpty())
1503         return false;
1504     v8::Handle<v8::Value> args[] = { o };
1505     function->Call(engine->global(), 1, args);
1506     return tc.HasCaught();
1507 }
1508
1509 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o, 
1510                                   const char *source, v8::Handle<v8::Value> result)
1511 {
1512     QString functionSource = QLatin1String("(function(object) { return ") + 
1513                              QLatin1String(source) + QLatin1String(" })");
1514     v8::TryCatch tc;
1515     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1516     if (tc.HasCaught())
1517         return false;
1518     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1519     if (function.IsEmpty())
1520         return false;
1521     v8::Handle<v8::Value> args[] = { o };
1522
1523     v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1524
1525     if (tc.HasCaught())
1526         return false;
1527
1528     return value->StrictEquals(result);
1529 }
1530
1531 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o, 
1532                                              const char *source)
1533 {
1534     QString functionSource = QLatin1String("(function(object) { return ") + 
1535                              QLatin1String(source) + QLatin1String(" })");
1536     v8::TryCatch tc;
1537     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1538     if (tc.HasCaught())
1539         return v8::Handle<v8::Value>();
1540     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1541     if (function.IsEmpty())
1542         return v8::Handle<v8::Value>();
1543     v8::Handle<v8::Value> args[] = { o };
1544
1545     v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1546
1547     if (tc.HasCaught())
1548         return v8::Handle<v8::Value>();
1549     return value;
1550 }
1551
1552 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1553 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1554 #define EVALUATE(source) evaluate(engine, object, source)
1555
1556 void tst_qdeclarativeecmascript::callQtInvokables()
1557 {
1558     MyInvokableObject o;
1559
1560     QDeclarativeEngine qmlengine;
1561     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1562     
1563     QV8Engine *engine = &ep->v8engine;
1564
1565     v8::HandleScope handle_scope;
1566     v8::Context::Scope scope(engine->context());
1567
1568     v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1569
1570     // Non-existent methods
1571     o.reset();
1572     QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1573     QCOMPARE(o.error(), false);
1574     QCOMPARE(o.invoked(), -1);
1575     QCOMPARE(o.actuals().count(), 0);
1576
1577     o.reset();
1578     QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1579     QCOMPARE(o.error(), false);
1580     QCOMPARE(o.invoked(), -1);
1581     QCOMPARE(o.actuals().count(), 0);
1582
1583     // Insufficient arguments
1584     o.reset();
1585     QVERIFY(EVALUATE_ERROR("object.method_int()"));
1586     QCOMPARE(o.error(), false);
1587     QCOMPARE(o.invoked(), -1);
1588     QCOMPARE(o.actuals().count(), 0);
1589
1590     o.reset();
1591     QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1592     QCOMPARE(o.error(), false);
1593     QCOMPARE(o.invoked(), -1);
1594     QCOMPARE(o.actuals().count(), 0);
1595
1596     // Excessive arguments
1597     o.reset();
1598     QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1599     QCOMPARE(o.error(), false);
1600     QCOMPARE(o.invoked(), 8);
1601     QCOMPARE(o.actuals().count(), 1);
1602     QCOMPARE(o.actuals().at(0), QVariant(10));
1603
1604     o.reset();
1605     QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1606     QCOMPARE(o.error(), false);
1607     QCOMPARE(o.invoked(), 9);
1608     QCOMPARE(o.actuals().count(), 2);
1609     QCOMPARE(o.actuals().at(0), QVariant(10));
1610     QCOMPARE(o.actuals().at(1), QVariant(11));
1611
1612     // Test return types
1613     o.reset();
1614     QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1615     QCOMPARE(o.error(), false);
1616     QCOMPARE(o.invoked(), 0);
1617     QCOMPARE(o.actuals().count(), 0);
1618
1619     o.reset();
1620     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1621     QCOMPARE(o.error(), false);
1622     QCOMPARE(o.invoked(), 1);
1623     QCOMPARE(o.actuals().count(), 0);
1624
1625     o.reset();
1626     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1627     QCOMPARE(o.error(), false);
1628     QCOMPARE(o.invoked(), 2);
1629     QCOMPARE(o.actuals().count(), 0);
1630
1631     o.reset();
1632     {
1633     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1634     QVERIFY(!ret.IsEmpty());
1635     QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1636     QCOMPARE(o.error(), false);
1637     QCOMPARE(o.invoked(), 3);
1638     QCOMPARE(o.actuals().count(), 0);
1639     }
1640
1641     o.reset();
1642     {
1643     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1644     QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1645     QCOMPARE(o.error(), false);
1646     QCOMPARE(o.invoked(), 4);
1647     QCOMPARE(o.actuals().count(), 0);
1648     }
1649
1650     o.reset();
1651     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1652     QCOMPARE(o.error(), false);
1653     QCOMPARE(o.invoked(), 5);
1654     QCOMPARE(o.actuals().count(), 0);
1655
1656     // XXX enable once qml/qtscript integration is implemented
1657 #if 0
1658     o.reset();
1659     {
1660     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1661     QVERIFY(ret->IsString());
1662     QCOMPARE(engine->toString(ret), QString("Hello world"));
1663     QCOMPARE(o.error(), false);
1664     QCOMPARE(o.invoked(), 6);
1665     QCOMPARE(o.actuals().count(), 0);
1666     }
1667 #endif
1668
1669     o.reset();
1670     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1671     QCOMPARE(o.error(), false);
1672     QCOMPARE(o.invoked(), 7);
1673     QCOMPARE(o.actuals().count(), 0);
1674
1675     // Test arg types
1676     o.reset();
1677     QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1678     QCOMPARE(o.error(), false);
1679     QCOMPARE(o.invoked(), 8);
1680     QCOMPARE(o.actuals().count(), 1);
1681     QCOMPARE(o.actuals().at(0), QVariant(94));
1682
1683     o.reset();
1684     QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1685     QCOMPARE(o.error(), false);
1686     QCOMPARE(o.invoked(), 8);
1687     QCOMPARE(o.actuals().count(), 1);
1688     QCOMPARE(o.actuals().at(0), QVariant(94));
1689
1690     o.reset();
1691     QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1692     QCOMPARE(o.error(), false);
1693     QCOMPARE(o.invoked(), 8);
1694     QCOMPARE(o.actuals().count(), 1);
1695     QCOMPARE(o.actuals().at(0), QVariant(0));
1696
1697     o.reset();
1698     QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1699     QCOMPARE(o.error(), false);
1700     QCOMPARE(o.invoked(), 8);
1701     QCOMPARE(o.actuals().count(), 1);
1702     QCOMPARE(o.actuals().at(0), QVariant(0));
1703
1704     o.reset();
1705     QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1706     QCOMPARE(o.error(), false);
1707     QCOMPARE(o.invoked(), 8);
1708     QCOMPARE(o.actuals().count(), 1);
1709     QCOMPARE(o.actuals().at(0), QVariant(0));
1710
1711     o.reset();
1712     QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1713     QCOMPARE(o.error(), false);
1714     QCOMPARE(o.invoked(), 8);
1715     QCOMPARE(o.actuals().count(), 1);
1716     QCOMPARE(o.actuals().at(0), QVariant(0));
1717
1718     o.reset();
1719     QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1720     QCOMPARE(o.error(), false);
1721     QCOMPARE(o.invoked(), 9);
1722     QCOMPARE(o.actuals().count(), 2);
1723     QCOMPARE(o.actuals().at(0), QVariant(122));
1724     QCOMPARE(o.actuals().at(1), QVariant(9));
1725
1726     o.reset();
1727     QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1728     QCOMPARE(o.error(), false);
1729     QCOMPARE(o.invoked(), 10);
1730     QCOMPARE(o.actuals().count(), 1);
1731     QCOMPARE(o.actuals().at(0), QVariant(94.3));
1732
1733     o.reset();
1734     QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1735     QCOMPARE(o.error(), false);
1736     QCOMPARE(o.invoked(), 10);
1737     QCOMPARE(o.actuals().count(), 1);
1738     QCOMPARE(o.actuals().at(0), QVariant(94.3));
1739
1740     o.reset();
1741     QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1742     QCOMPARE(o.error(), false);
1743     QCOMPARE(o.invoked(), 10);
1744     QCOMPARE(o.actuals().count(), 1);
1745     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1746
1747     o.reset();
1748     QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1749     QCOMPARE(o.error(), false);
1750     QCOMPARE(o.invoked(), 10);
1751     QCOMPARE(o.actuals().count(), 1);
1752     QCOMPARE(o.actuals().at(0), QVariant(0));
1753
1754     o.reset();
1755     QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1756     QCOMPARE(o.error(), false);
1757     QCOMPARE(o.invoked(), 10);
1758     QCOMPARE(o.actuals().count(), 1);
1759     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1760
1761     o.reset();
1762     QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1763     QCOMPARE(o.error(), false);
1764     QCOMPARE(o.invoked(), 10);
1765     QCOMPARE(o.actuals().count(), 1);
1766     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1767
1768     o.reset();
1769     QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1770     QCOMPARE(o.error(), false);
1771     QCOMPARE(o.invoked(), 11);
1772     QCOMPARE(o.actuals().count(), 1);
1773     QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1774
1775     o.reset();
1776     QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1777     QCOMPARE(o.error(), false);
1778     QCOMPARE(o.invoked(), 11);
1779     QCOMPARE(o.actuals().count(), 1);
1780     QCOMPARE(o.actuals().at(0), QVariant("19"));
1781
1782     o.reset();
1783     {
1784     QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1785     QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1786     QCOMPARE(o.error(), false);
1787     QCOMPARE(o.invoked(), 11);
1788     QCOMPARE(o.actuals().count(), 1);
1789     QCOMPARE(o.actuals().at(0), QVariant(expected));
1790     }
1791
1792     o.reset();
1793     QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1794     QCOMPARE(o.error(), false);
1795     QCOMPARE(o.invoked(), 11);
1796     QCOMPARE(o.actuals().count(), 1);
1797     QCOMPARE(o.actuals().at(0), QVariant(QString()));
1798
1799     o.reset();
1800     QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1801     QCOMPARE(o.error(), false);
1802     QCOMPARE(o.invoked(), 11);
1803     QCOMPARE(o.actuals().count(), 1);
1804     QCOMPARE(o.actuals().at(0), QVariant(QString()));
1805
1806     o.reset();
1807     QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1808     QCOMPARE(o.error(), false);
1809     QCOMPARE(o.invoked(), 12);
1810     QCOMPARE(o.actuals().count(), 1);
1811     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1812
1813     o.reset();
1814     QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1815     QCOMPARE(o.error(), false);
1816     QCOMPARE(o.invoked(), 12);
1817     QCOMPARE(o.actuals().count(), 1);
1818     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1819
1820     o.reset();
1821     QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1822     QCOMPARE(o.error(), false);
1823     QCOMPARE(o.invoked(), 12);
1824     QCOMPARE(o.actuals().count(), 1);
1825     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1826
1827     o.reset();
1828     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
1829     QCOMPARE(o.error(), false);
1830     QCOMPARE(o.invoked(), 12);
1831     QCOMPARE(o.actuals().count(), 1);
1832     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1833
1834     o.reset();
1835     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
1836     QCOMPARE(o.error(), false);
1837     QCOMPARE(o.invoked(), 12);
1838     QCOMPARE(o.actuals().count(), 1);
1839     QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
1840
1841     o.reset();
1842     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
1843     QCOMPARE(o.error(), false);
1844     QCOMPARE(o.invoked(), 12);
1845     QCOMPARE(o.actuals().count(), 1);
1846     QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
1847
1848     o.reset();
1849     QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
1850     QCOMPARE(o.error(), false);
1851     QCOMPARE(o.invoked(), 13);
1852     QCOMPARE(o.actuals().count(), 1);
1853     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1854
1855     o.reset();
1856     QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
1857     QCOMPARE(o.error(), false);
1858     QCOMPARE(o.invoked(), 13);
1859     QCOMPARE(o.actuals().count(), 1);
1860     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1861
1862     o.reset();
1863     QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
1864     QCOMPARE(o.error(), false);
1865     QCOMPARE(o.invoked(), 13);
1866     QCOMPARE(o.actuals().count(), 1);
1867     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1868
1869     o.reset();
1870     QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
1871     QCOMPARE(o.error(), false);
1872     QCOMPARE(o.invoked(), 13);
1873     QCOMPARE(o.actuals().count(), 1);
1874     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1875
1876     o.reset();
1877     QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
1878     QCOMPARE(o.error(), false);
1879     QCOMPARE(o.invoked(), 13);
1880     QCOMPARE(o.actuals().count(), 1);
1881     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
1882
1883     // XXX enable once qml/qtscript integration is implemented
1884 #if 0
1885     o.reset();
1886     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
1887     QCOMPARE(o.error(), false);
1888     QCOMPARE(o.invoked(), 14);
1889     QCOMPARE(o.actuals().count(), 1);
1890     QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isNull());
1891
1892     o.reset();
1893     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
1894     QCOMPARE(o.error(), false);
1895     QCOMPARE(o.invoked(), 14);
1896     QCOMPARE(o.actuals().count(), 1);
1897     QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isUndefined());
1898
1899     o.reset();
1900     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
1901     QCOMPARE(o.error(), false);
1902     QCOMPARE(o.invoked(), 14);
1903     QCOMPARE(o.actuals().count(), 1);
1904     QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).strictlyEquals(QScriptValue(engine, 19)));
1905
1906     o.reset();
1907     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
1908     QCOMPARE(o.error(), false);
1909     QCOMPARE(o.invoked(), 14);
1910     QCOMPARE(o.actuals().count(), 1);
1911     QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isArray());
1912
1913     o.reset();
1914     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
1915     QCOMPARE(o.error(), false);
1916     QCOMPARE(o.invoked(), 15);
1917     QCOMPARE(o.actuals().count(), 2);
1918     QCOMPARE(o.actuals().at(0), QVariant(4));
1919     QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isNull());
1920
1921     o.reset();
1922     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
1923     QCOMPARE(o.error(), false);
1924     QCOMPARE(o.invoked(), 15);
1925     QCOMPARE(o.actuals().count(), 2);
1926     QCOMPARE(o.actuals().at(0), QVariant(8));
1927     QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isUndefined());
1928
1929     o.reset();
1930     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
1931     QCOMPARE(o.error(), false);
1932     QCOMPARE(o.invoked(), 15);
1933     QCOMPARE(o.actuals().count(), 2);
1934     QCOMPARE(o.actuals().at(0), QVariant(3));
1935     QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).strictlyEquals(QScriptValue(engine, 19)));
1936
1937     o.reset();
1938     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
1939     QCOMPARE(o.error(), false);
1940     QCOMPARE(o.invoked(), 15);
1941     QCOMPARE(o.actuals().count(), 2);
1942     QCOMPARE(o.actuals().at(0), QVariant(44));
1943     QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isArray());
1944 #endif
1945
1946     o.reset();
1947     QVERIFY(EVALUATE_ERROR("object.method_overload()"));
1948     QCOMPARE(o.error(), false);
1949     QCOMPARE(o.invoked(), -1);
1950     QCOMPARE(o.actuals().count(), 0);
1951
1952     o.reset();
1953     QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
1954     QCOMPARE(o.error(), false);
1955     QCOMPARE(o.invoked(), 16);
1956     QCOMPARE(o.actuals().count(), 1);
1957     QCOMPARE(o.actuals().at(0), QVariant(10));
1958
1959     o.reset();
1960     QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
1961     QCOMPARE(o.error(), false);
1962     QCOMPARE(o.invoked(), 17);
1963     QCOMPARE(o.actuals().count(), 2);
1964     QCOMPARE(o.actuals().at(0), QVariant(10));
1965     QCOMPARE(o.actuals().at(1), QVariant(11));
1966
1967     o.reset();
1968     QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
1969     QCOMPARE(o.error(), false);
1970     QCOMPARE(o.invoked(), 18);
1971     QCOMPARE(o.actuals().count(), 1);
1972     QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
1973
1974     o.reset();
1975     QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
1976     QCOMPARE(o.error(), false);
1977     QCOMPARE(o.invoked(), 19);
1978     QCOMPARE(o.actuals().count(), 1);
1979     QCOMPARE(o.actuals().at(0), QVariant(9));
1980
1981     o.reset();
1982     QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
1983     QCOMPARE(o.error(), false);
1984     QCOMPARE(o.invoked(), 20);
1985     QCOMPARE(o.actuals().count(), 2);
1986     QCOMPARE(o.actuals().at(0), QVariant(10));
1987     QCOMPARE(o.actuals().at(1), QVariant(19));
1988
1989     o.reset();
1990     QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
1991     QCOMPARE(o.error(), false);
1992     QCOMPARE(o.invoked(), 20);
1993     QCOMPARE(o.actuals().count(), 2);
1994     QCOMPARE(o.actuals().at(0), QVariant(10));
1995     QCOMPARE(o.actuals().at(1), QVariant(13));
1996
1997     o.reset();
1998     QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
1999     QCOMPARE(o.error(), false);
2000     QCOMPARE(o.invoked(), -3);
2001     QCOMPARE(o.actuals().count(), 1);
2002     QCOMPARE(o.actuals().at(0), QVariant(9));
2003
2004     o.reset();
2005     QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2006     QCOMPARE(o.error(), false);
2007     QCOMPARE(o.invoked(), 21);
2008     QCOMPARE(o.actuals().count(), 2);
2009     QCOMPARE(o.actuals().at(0), QVariant(9));
2010     QCOMPARE(o.actuals().at(1), QVariant());
2011
2012     o.reset();
2013     QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2014     QCOMPARE(o.error(), false);
2015     QCOMPARE(o.invoked(), 21);
2016     QCOMPARE(o.actuals().count(), 2);
2017     QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2018     QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2019 }
2020
2021 // QTBUG-13047 (check that you can pass registered object types as args)
2022 void tst_qdeclarativeecmascript::invokableObjectArg()
2023 {
2024     QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2025
2026     QObject *o = component.create();
2027     QVERIFY(o);
2028     MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2029     QVERIFY(qmlobject);
2030     QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2031
2032     delete o;
2033 }
2034
2035 // QTBUG-13047 (check that you can return registered object types from methods)
2036 void tst_qdeclarativeecmascript::invokableObjectRet()
2037 {
2038     QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2039
2040     QObject *o = component.create();
2041     QVERIFY(o);
2042     QCOMPARE(o->property("test").toBool(), true);
2043     delete o;
2044 }
2045
2046 // QTBUG-5675
2047 void tst_qdeclarativeecmascript::listToVariant()
2048 {
2049     QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2050
2051     MyQmlContainer container;
2052
2053     QDeclarativeContext context(engine.rootContext());
2054     context.setContextObject(&container);
2055
2056     QObject *object = component.create(&context);
2057     QVERIFY(object != 0);
2058
2059     QVariant v = object->property("test");
2060     QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2061     QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2062
2063     delete object;
2064 }
2065
2066 // QTBUG-7957
2067 void tst_qdeclarativeecmascript::multiEngineObject()
2068 {
2069     MyQmlObject obj;
2070     obj.setStringProperty("Howdy planet");
2071
2072     QDeclarativeEngine e1;
2073     e1.rootContext()->setContextProperty("thing", &obj);
2074     QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2075
2076     QDeclarativeEngine e2;
2077     e2.rootContext()->setContextProperty("thing", &obj);
2078     QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2079
2080     QObject *o1 = c1.create();
2081     QObject *o2 = c2.create();
2082
2083     QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2084     QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2085
2086     delete o2;
2087     delete o1;
2088 }
2089
2090 // Test that references to QObjects are cleanup when the object is destroyed
2091 void tst_qdeclarativeecmascript::deletedObject()
2092 {
2093     QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2094
2095     QObject *object = component.create();
2096
2097     QCOMPARE(object->property("test1").toBool(), true);
2098     QCOMPARE(object->property("test2").toBool(), true);
2099     QCOMPARE(object->property("test3").toBool(), true);
2100     QCOMPARE(object->property("test4").toBool(), true);
2101
2102     delete object;
2103 }
2104
2105 void tst_qdeclarativeecmascript::attachedPropertyScope()
2106 {
2107     QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2108
2109     QObject *object = component.create();
2110     QVERIFY(object != 0);
2111
2112     MyQmlAttachedObject *attached = 
2113         qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2114     QVERIFY(attached != 0);
2115
2116     QCOMPARE(object->property("value2").toInt(), 0);
2117
2118     attached->emitMySignal();
2119
2120     QCOMPARE(object->property("value2").toInt(), 9);
2121
2122     delete object;
2123 }
2124
2125 void tst_qdeclarativeecmascript::scriptConnect()
2126 {
2127     {
2128         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2129
2130         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2131         QVERIFY(object != 0);
2132
2133         QCOMPARE(object->property("test").toBool(), false);
2134         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2135         QCOMPARE(object->property("test").toBool(), true);
2136
2137         delete object;
2138     }
2139
2140     {
2141         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2142
2143         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2144         QVERIFY(object != 0);
2145
2146         QCOMPARE(object->property("test").toBool(), false);
2147         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2148         QCOMPARE(object->property("test").toBool(), true);
2149
2150         delete object;
2151     }
2152
2153     {
2154         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2155
2156         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2157         QVERIFY(object != 0);
2158
2159         QCOMPARE(object->property("test").toBool(), false);
2160         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2161         QCOMPARE(object->property("test").toBool(), true);
2162
2163         delete object;
2164     }
2165
2166     {
2167         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2168
2169         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2170         QVERIFY(object != 0);
2171
2172         QCOMPARE(object->methodCalled(), false);
2173         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2174         QCOMPARE(object->methodCalled(), true);
2175
2176         delete object;
2177     }
2178
2179     {
2180         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2181
2182         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2183         QVERIFY(object != 0);
2184
2185         QCOMPARE(object->methodCalled(), false);
2186         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2187         QCOMPARE(object->methodCalled(), true);
2188
2189         delete object;
2190     }
2191
2192     {
2193         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2194
2195         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2196         QVERIFY(object != 0);
2197
2198         QCOMPARE(object->property("test").toInt(), 0);
2199         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2200         QCOMPARE(object->property("test").toInt(), 2);
2201
2202         delete object;
2203     }
2204 }
2205
2206 void tst_qdeclarativeecmascript::scriptDisconnect()
2207 {
2208     {
2209         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2210
2211         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2212         QVERIFY(object != 0);
2213
2214         QCOMPARE(object->property("test").toInt(), 0);
2215         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2216         QCOMPARE(object->property("test").toInt(), 1);
2217         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2218         QCOMPARE(object->property("test").toInt(), 2);
2219         emit object->basicSignal();
2220         QCOMPARE(object->property("test").toInt(), 2);
2221         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2222         QCOMPARE(object->property("test").toInt(), 2);
2223
2224         delete object;
2225     }
2226
2227     {
2228         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2229
2230         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2231         QVERIFY(object != 0);
2232
2233         QCOMPARE(object->property("test").toInt(), 0);
2234         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2235         QCOMPARE(object->property("test").toInt(), 1);
2236         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2237         QCOMPARE(object->property("test").toInt(), 2);
2238         emit object->basicSignal();
2239         QCOMPARE(object->property("test").toInt(), 2);
2240         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2241         QCOMPARE(object->property("test").toInt(), 2);
2242
2243         delete object;
2244     }
2245
2246     {
2247         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2248
2249         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2250         QVERIFY(object != 0);
2251
2252         QCOMPARE(object->property("test").toInt(), 0);
2253         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2254         QCOMPARE(object->property("test").toInt(), 1);
2255         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2256         QCOMPARE(object->property("test").toInt(), 2);
2257         emit object->basicSignal();
2258         QCOMPARE(object->property("test").toInt(), 2);
2259         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2260         QCOMPARE(object->property("test").toInt(), 3);
2261
2262         delete object;
2263     }
2264     {
2265         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2266
2267         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2268         QVERIFY(object != 0);
2269
2270         QCOMPARE(object->property("test").toInt(), 0);
2271         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2272         QCOMPARE(object->property("test").toInt(), 1);
2273         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2274         QCOMPARE(object->property("test").toInt(), 2);
2275         emit object->basicSignal();
2276         QCOMPARE(object->property("test").toInt(), 2);
2277         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2278         QCOMPARE(object->property("test").toInt(), 3);
2279
2280         delete object;
2281     }
2282 }
2283
2284 class OwnershipObject : public QObject
2285 {
2286     Q_OBJECT
2287 public:
2288     OwnershipObject() { object = new QObject; }
2289
2290     QPointer<QObject> object;
2291
2292 public slots:
2293     QObject *getObject() { return object; }
2294 };
2295
2296 void tst_qdeclarativeecmascript::ownership()
2297 {
2298     OwnershipObject own;
2299     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2300     context->setContextObject(&own);
2301
2302     {
2303         QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2304
2305         QVERIFY(own.object != 0);
2306
2307         QObject *object = component.create(context);
2308
2309         engine.collectGarbage();
2310
2311         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2312
2313         QVERIFY(own.object == 0);
2314
2315         delete object;
2316     }
2317
2318     own.object = new QObject(&own);
2319
2320     {
2321         QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2322
2323         QVERIFY(own.object != 0);
2324
2325         QObject *object = component.create(context);
2326         
2327         engine.collectGarbage();
2328
2329         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2330
2331         QVERIFY(own.object != 0);
2332
2333         delete object;
2334     }
2335
2336     delete context;
2337 }
2338
2339 class CppOwnershipReturnValue : public QObject
2340 {
2341     Q_OBJECT
2342 public:
2343     CppOwnershipReturnValue() : value(0) {}
2344     ~CppOwnershipReturnValue() { delete value; }
2345
2346     Q_INVOKABLE QObject *create() {
2347         value = new QObject;
2348         QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2349         return value;
2350     }
2351
2352     Q_INVOKABLE MyQmlObject *createQmlObject() {
2353         MyQmlObject *rv = new MyQmlObject;
2354         value = rv;
2355         return rv;
2356     }
2357
2358     QPointer<QObject> value;
2359 };
2360
2361 // QTBUG-15695.  
2362 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2363 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2364 {
2365     CppOwnershipReturnValue source;
2366
2367     {
2368     QDeclarativeEngine engine;
2369     engine.rootContext()->setContextProperty("source", &source);
2370
2371     QVERIFY(source.value == 0);
2372
2373     QDeclarativeComponent component(&engine);
2374     component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2375
2376     QObject *object = component.create();
2377
2378     QVERIFY(object != 0);
2379     QVERIFY(source.value != 0);
2380
2381     delete object;
2382     }
2383
2384     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2385
2386     QVERIFY(source.value != 0);
2387 }
2388
2389 // QTBUG-15697
2390 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2391 {
2392     CppOwnershipReturnValue source;
2393
2394     {
2395     QDeclarativeEngine engine;
2396     engine.rootContext()->setContextProperty("source", &source);
2397
2398     QVERIFY(source.value == 0);
2399
2400     QDeclarativeComponent component(&engine);
2401     component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2402
2403     QObject *object = component.create();
2404
2405     QVERIFY(object != 0);
2406     QVERIFY(source.value != 0);
2407
2408     delete object;
2409     }
2410
2411     engine.collectGarbage();
2412     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2413
2414     QVERIFY(source.value == 0);
2415 }
2416
2417 class QListQObjectMethodsObject : public QObject
2418 {
2419     Q_OBJECT
2420 public:
2421     QListQObjectMethodsObject() {
2422         m_objects.append(new MyQmlObject());
2423         m_objects.append(new MyQmlObject());
2424     }
2425
2426     ~QListQObjectMethodsObject() {
2427         qDeleteAll(m_objects);
2428     }
2429
2430 public slots:
2431     QList<QObject *> getObjects() { return m_objects; }
2432
2433 private:
2434     QList<QObject *> m_objects;
2435 };
2436
2437 // Tests that returning a QList<QObject*> from a method works
2438 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2439 {
2440     QListQObjectMethodsObject obj;
2441     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2442     context->setContextObject(&obj);
2443
2444     QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2445
2446     QObject *object = component.create(context);
2447
2448     QCOMPARE(object->property("test").toInt(), 2);
2449     QCOMPARE(object->property("test2").toBool(), true);
2450
2451     delete object;
2452     delete context;
2453 }
2454
2455 // QTBUG-9205
2456 void tst_qdeclarativeecmascript::strictlyEquals()
2457 {
2458     QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2459
2460     QObject *object = component.create();
2461     QVERIFY(object != 0);
2462
2463     QCOMPARE(object->property("test1").toBool(), true);
2464     QCOMPARE(object->property("test2").toBool(), true);
2465     QCOMPARE(object->property("test3").toBool(), true);
2466     QCOMPARE(object->property("test4").toBool(), true);
2467     QCOMPARE(object->property("test5").toBool(), true);
2468     QCOMPARE(object->property("test6").toBool(), true);
2469     QCOMPARE(object->property("test7").toBool(), true);
2470     QCOMPARE(object->property("test8").toBool(), true);
2471
2472     delete object;
2473 }
2474
2475 void tst_qdeclarativeecmascript::compiled()
2476 {
2477     QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2478
2479     QObject *object = component.create();
2480     QVERIFY(object != 0);
2481
2482     QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2483     QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2484     QCOMPARE(object->property("test3").toBool(), true);
2485     QCOMPARE(object->property("test4").toBool(), false);
2486     QCOMPARE(object->property("test5").toBool(), false);
2487     QCOMPARE(object->property("test6").toBool(), true);
2488
2489     QCOMPARE(object->property("test7").toInt(), 185);
2490     QCOMPARE(object->property("test8").toInt(), 167);
2491     QCOMPARE(object->property("test9").toBool(), true);
2492     QCOMPARE(object->property("test10").toBool(), false);
2493     QCOMPARE(object->property("test11").toBool(), false);
2494     QCOMPARE(object->property("test12").toBool(), true);
2495
2496     QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2497     QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2498     QCOMPARE(object->property("test15").toBool(), false);
2499     QCOMPARE(object->property("test16").toBool(), true);
2500
2501     QCOMPARE(object->property("test17").toInt(), 5);
2502     QCOMPARE(object->property("test18").toReal(), qreal(176));
2503     QCOMPARE(object->property("test19").toInt(), 7);
2504     QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2505     QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2506     QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2507     QCOMPARE(object->property("test23").toBool(), true);
2508     QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2509     QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2510
2511     delete object;
2512 }
2513
2514 // Test that numbers assigned in bindings as strings work consistently
2515 void tst_qdeclarativeecmascript::numberAssignment()
2516 {
2517     QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2518
2519     QObject *object = component.create();
2520     QVERIFY(object != 0);
2521
2522     QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2523     QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2524     QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2525     QCOMPARE(object->property("test3"), QVariant((qreal)6));
2526     QCOMPARE(object->property("test4"), QVariant((qreal)6));
2527
2528     QCOMPARE(object->property("test5"), QVariant((int)7));
2529     QCOMPARE(object->property("test6"), QVariant((int)7));
2530     QCOMPARE(object->property("test7"), QVariant((int)6));
2531     QCOMPARE(object->property("test8"), QVariant((int)6));
2532
2533     QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2534     QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2535     QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2536     QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2537
2538     delete object;
2539 }
2540
2541 void tst_qdeclarativeecmascript::propertySplicing()
2542 {
2543     QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2544
2545     QObject *object = component.create();
2546     QVERIFY(object != 0);
2547
2548     QCOMPARE(object->property("test").toBool(), true);
2549
2550     delete object;
2551 }
2552
2553 // QTBUG-16683
2554 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2555 {
2556     QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2557
2558     MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2559     QVERIFY(object != 0);
2560
2561     MyQmlObject::MyType type;
2562     type.value = 0x8971123;
2563     emit object->signalWithUnknownType(type);
2564
2565     MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2566
2567     QCOMPARE(result.value, type.value);
2568
2569
2570     delete object;
2571 }
2572
2573 void tst_qdeclarativeecmascript::moduleApi()
2574 {
2575     QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
2576     QObject *object = component.create();
2577     QVERIFY(object != 0);
2578     QCOMPARE(object->property("existingUriTest").toInt(), 20);
2579     QCOMPARE(object->property("scriptTest").toInt(), 13);
2580     QCOMPARE(object->property("qobjectTest").toInt(), 20);
2581     QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
2582     QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
2583     QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
2584     QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
2585     delete object;
2586
2587     // test that caching of module apis works correctly.
2588     QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
2589     object = componentTwo.create();
2590     QVERIFY(object != 0);
2591     QCOMPARE(object->property("existingUriTest").toInt(), 20);
2592     QCOMPARE(object->property("scriptTest").toInt(), 13);            // shouldn't have incremented.
2593     QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);   // shouldn't have incremented.
2594     delete object;
2595
2596     // test that writing to a property of module apis works correctly.
2597     QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
2598     QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
2599     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2600     object = componentThree.create();
2601     QVERIFY(object != 0);
2602     QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2603     QCOMPARE(object->property("writableProperty").toInt(), 50);
2604     QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
2605     QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
2606     QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2607     QCOMPARE(object->property("writableProperty").toInt(), 30);
2608     delete object;
2609
2610     QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
2611     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2612     object = failOne.create();
2613     QVERIFY(object == 0); // should have failed: invalid major version
2614
2615     QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
2616     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2617     object = failTwo.create();
2618     QVERIFY(object == 0); // should have failed: invalid minor version
2619 }
2620
2621 void tst_qdeclarativeecmascript::importScripts()
2622 {
2623     QObject *object = 0;
2624
2625     // first, ensure that the required behaviour works.
2626     QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2627     object = component.create();
2628     QVERIFY(object != 0);
2629     QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2630     QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2631     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2632     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2633     delete object;
2634
2635     QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2636     object = componentTwo.create();
2637     QVERIFY(object != 0);
2638     QCOMPARE(object->property("componentError"), QVariant(5));
2639     delete object;
2640
2641     // then, ensure that unintended behaviour does not work.
2642     QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2643     QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Result of expression 'TestScriptImport.ImportOneJs' [undefined] is not an object.");
2644     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2645     object = failOneComponent.create();
2646     QVERIFY(object != 0);
2647     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2648     delete object;
2649     QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2650     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2651     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2652     object = failTwoComponent.create();
2653     QVERIFY(object != 0);
2654     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2655     delete object;
2656     QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2657     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Result of expression 'testQtObject.TestModuleImport.JsQtTest' [undefined] is not an object.");
2658     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2659     object = failThreeComponent.create();
2660     QVERIFY(object != 0);
2661     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2662     delete object;
2663     QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2664     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2665     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2666     object = failFourComponent.create();
2667     QVERIFY(object != 0);
2668     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2669     delete object;
2670     QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2671     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2672     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2673     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2674     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2675     object = failFiveComponent.create();
2676     QVERIFY(object != 0);
2677     QCOMPARE(object->property("componentError"), QVariant(0));
2678     delete object;
2679
2680     // also, test that importing scripts with .pragma library works as required
2681     QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2682     object = pragmaLibraryComponent.create();
2683     QVERIFY(object != 0);
2684     QCOMPARE(object->property("testValue"), QVariant(31));
2685     delete object;
2686
2687     // and that .pragma library scripts don't inherit imports from any .qml file
2688     QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2689     object = pragmaLibraryComponentTwo.create();
2690     QVERIFY(object != 0);
2691     QCOMPARE(object->property("testValue"), QVariant(0));
2692     delete object;
2693 }
2694
2695 void tst_qdeclarativeecmascript::scarceResources()
2696 {
2697     QPixmap origPixmap(100, 100);
2698     origPixmap.fill(Qt::blue);
2699
2700     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2701     ScarceResourceObject *eo = 0;
2702     QObject *object = 0;
2703
2704     // in the following three cases, the instance created from the component
2705     // has a property which is a copy of the scarce resource; hence, the
2706     // resource should NOT be detached prior to deletion of the object instance,
2707     // unless the resource is destroyed explicitly.
2708     QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2709     object = component.create();
2710     QVERIFY(object != 0);
2711     QVERIFY(object->property("scarceResourceCopy").isValid());
2712     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2713     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2714     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2715     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2716     delete object;
2717
2718     QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2719     object = componentTwo.create();
2720     QVERIFY(object != 0);
2721     QVERIFY(object->property("scarceResourceCopy").isValid());
2722     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2723     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2724     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2725     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2726     delete object;
2727
2728     QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
2729     object = componentThree.create();
2730     QVERIFY(object != 0);
2731     QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
2732     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2733     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2734     QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
2735     delete object;
2736
2737     // in the following three cases, no other copy should exist in memory,
2738     // and so it should be detached (unless explicitly preserved).
2739     QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
2740     object = componentFour.create();
2741     QVERIFY(object != 0);
2742     QVERIFY(object->property("scarceResourceTest").isValid());
2743     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2744     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2745     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2746     QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
2747     delete object;
2748
2749     QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
2750     object = componentFive.create();
2751     QVERIFY(object != 0);
2752     QVERIFY(object->property("scarceResourceTest").isValid());
2753     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2754     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2755     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2756     QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
2757     delete object;
2758
2759     QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
2760     object = componentSix.create();
2761     QVERIFY(object != 0);
2762     QVERIFY(object->property("scarceResourceTest").isValid());
2763     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2764     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2765     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2766     QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
2767     delete object;
2768
2769     // test that scarce resources are handled correctly for imports
2770     QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
2771     object = componentSeven.create();
2772     QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
2773     QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
2774     delete object;
2775
2776     QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
2777     object = componentEight.create();
2778     QVERIFY(object != 0);
2779     QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
2780     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2781     delete object;
2782
2783     QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
2784     object = componentNine.create();
2785     QVERIFY(object != 0);
2786     QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
2787     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2788     QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
2789     QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
2790     QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
2791     QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
2792     delete object;
2793
2794     // test that scarce resources are handled properly in signal invocation
2795     QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
2796     object = componentTen.create();
2797     QVERIFY(object != 0);
2798     QObject *srsc = object->findChild<QObject*>("srsc");
2799     QVERIFY(srsc);
2800     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
2801     QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
2802     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2803     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2804     QMetaObject::invokeMethod(srsc, "testSignal");
2805     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
2806     QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
2807     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2808     QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
2809     QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
2810     QVERIFY(srsc->property("scarceResourceCopy").isValid());
2811     QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2812     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2813     QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
2814     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2815     delete object;
2816
2817     // test that scarce resources are handled properly from js functions in qml files
2818     QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
2819     object = componentEleven.create();
2820     QVERIFY(object != 0);
2821     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2822     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2823     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2824     QMetaObject::invokeMethod(object, "retrieveScarceResource");
2825     QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
2826     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2827     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2828     QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
2829     QMetaObject::invokeMethod(object, "releaseScarceResource");
2830     QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
2831     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2832     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2833     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2834     delete object;
2835
2836     // test that if an exception occurs while invoking js function from cpp, that the resources are released.
2837     QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
2838     object = componentTwelve.create();
2839     QVERIFY(object != 0);
2840     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2841     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2842     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2843     QString srp_name = object->property("srp_name").toString();
2844     QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
2845     QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
2846     QMetaObject::invokeMethod(object, "retrieveScarceResource");
2847     QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
2848     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2849     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2850     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2851     delete object;
2852 }
2853
2854 void tst_qdeclarativeecmascript::propertyChangeSlots()
2855 {
2856     // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
2857     QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
2858     QObject *object = component.create();
2859     QVERIFY(object != 0);
2860     delete object;
2861
2862     // ensure that invalid property names fail properly.
2863     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2864     QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
2865     QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
2866     QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
2867     object = e1.create();
2868     QVERIFY(object == 0);
2869     delete object;
2870
2871     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2872     QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
2873     expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
2874     QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
2875     object = e2.create();
2876     QVERIFY(object == 0);
2877     delete object;
2878
2879     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2880     QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
2881     expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
2882     QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
2883     object = e3.create();
2884     QVERIFY(object == 0);
2885     delete object;
2886
2887     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2888     QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
2889     expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
2890     QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
2891     object = e4.create();
2892     QVERIFY(object == 0);
2893     delete object;
2894 }
2895
2896 // Test that assigning a null object works 
2897 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
2898 void tst_qdeclarativeecmascript::nullObjectBinding()
2899 {
2900     QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
2901
2902     QObject *object = component.create();
2903     QVERIFY(object != 0);
2904
2905     QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
2906
2907     delete object;
2908 }
2909
2910 // Test that bindings don't evaluate once the engine has been destroyed
2911 void tst_qdeclarativeecmascript::deletedEngine()
2912 {
2913     QDeclarativeEngine *engine = new QDeclarativeEngine;
2914     QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
2915
2916     QObject *object = component.create();
2917     QVERIFY(object != 0);
2918
2919     QCOMPARE(object->property("a").toInt(), 39);
2920     object->setProperty("b", QVariant(9));
2921     QCOMPARE(object->property("a").toInt(), 117);
2922
2923     delete engine;
2924
2925     QCOMPARE(object->property("a").toInt(), 117);
2926     object->setProperty("b", QVariant(10));
2927     QCOMPARE(object->property("a").toInt(), 117);
2928
2929     delete object;
2930 }
2931
2932 // Test the crashing part of QTBUG-9705
2933 void tst_qdeclarativeecmascript::libraryScriptAssert()
2934 {
2935     QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
2936
2937     QObject *object = component.create();
2938     QVERIFY(object != 0);
2939
2940     delete object;
2941 }
2942
2943 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
2944 {
2945     QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
2946
2947     QObject *object = component.create();
2948     QVERIFY(object != 0);
2949
2950     QCOMPARE(object->property("test1").toInt(), 10);
2951     QCOMPARE(object->property("test2").toInt(), 11);
2952
2953     object->setProperty("runTest", true);
2954
2955     QCOMPARE(object->property("test1"), QVariant());
2956     QCOMPARE(object->property("test2"), QVariant());
2957
2958
2959     delete object;
2960 }
2961
2962 void tst_qdeclarativeecmascript::qtbug_9792()
2963 {
2964     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
2965
2966     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2967
2968     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
2969     QVERIFY(object != 0);
2970
2971     QTest::ignoreMessage(QtDebugMsg, "Hello world!");
2972     object->basicSignal();
2973
2974     delete context;
2975
2976     transientErrorsMsgCount = 0;
2977     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
2978
2979     object->basicSignal();
2980     
2981     qInstallMsgHandler(old);
2982
2983     QCOMPARE(transientErrorsMsgCount, 0);
2984
2985     delete object;
2986 }
2987
2988 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
2989 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
2990 {
2991     QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
2992
2993     QObject *o = component.create();
2994     QVERIFY(o != 0);
2995
2996     QObject *nested = qvariant_cast<QObject *>(o->property("object"));
2997     QVERIFY(nested != 0);
2998
2999     QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3000
3001     delete nested;
3002     nested = qvariant_cast<QObject *>(o->property("object"));
3003     QVERIFY(nested == 0);
3004
3005     // If the bug is present, the next line will crash
3006     delete o;
3007 }
3008
3009 // Test that we shut down without stupid warnings
3010 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3011 {
3012     {
3013     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3014
3015     QObject *o = component.create();
3016
3017     transientErrorsMsgCount = 0;
3018     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3019
3020     delete o;
3021
3022     qInstallMsgHandler(old);
3023
3024     QCOMPARE(transientErrorsMsgCount, 0);
3025     }
3026
3027
3028     {
3029     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3030
3031     QObject *o = component.create();
3032
3033     transientErrorsMsgCount = 0;
3034     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3035
3036     delete o;
3037
3038     qInstallMsgHandler(old);
3039
3040     QCOMPARE(transientErrorsMsgCount, 0);
3041     }
3042 }
3043
3044 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3045 {
3046     {
3047     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3048
3049     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3050     QVERIFY(o != 0);
3051
3052     QVERIFY(o->objectProperty() != 0);
3053
3054     o->setProperty("runTest", true);
3055
3056     QVERIFY(o->objectProperty() == 0);
3057
3058     delete o;
3059     }
3060
3061     {
3062     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3063
3064     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3065     QVERIFY(o != 0);
3066
3067     QVERIFY(o->objectProperty() == 0);
3068
3069     delete o;
3070     }
3071 }
3072
3073 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3074 {
3075     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3076
3077     QString url = component.url().toString();
3078     QString warning = url + ":4: Unable to assign a function to a property.";
3079     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3080     
3081     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3082     QVERIFY(o != 0);
3083
3084     QVERIFY(!o->property("a").isValid());
3085
3086     delete o;
3087 }
3088
3089 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3090 {
3091     QFETCH(QString, triggerProperty);
3092
3093     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3094     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3095
3096     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3097     QVERIFY(o != 0);
3098     QVERIFY(!o->property("a").isValid());
3099
3100     o->setProperty("aNumber", QVariant(5));
3101     o->setProperty(triggerProperty.toUtf8().constData(), true);
3102     QCOMPARE(o->property("a"), QVariant(50));
3103
3104     o->setProperty("aNumber", QVariant(10));
3105     QCOMPARE(o->property("a"), QVariant(100));
3106
3107     delete o;
3108 }
3109
3110 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3111 {
3112     QTest::addColumn<QString>("triggerProperty");
3113
3114     QTest::newRow("assign to property") << "assignToProperty";
3115     QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3116
3117     QTest::newRow("assign to value type") << "assignToValueType";
3118
3119     QTest::newRow("use 'this'") << "assignWithThis";
3120     QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3121 }
3122
3123 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3124 {
3125     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3126     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3127
3128     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3129     QVERIFY(o != 0);
3130     QVERIFY(!o->property("a").isValid());
3131
3132     o->setProperty("assignFuncWithoutReturn", true);
3133     QVERIFY(!o->property("a").isValid());
3134
3135     QString url = component.url().toString();
3136     QString warning = url + ":67: Unable to assign QString to int";
3137     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3138     o->setProperty("assignWrongType", true);
3139
3140     warning = url + ":71: Unable to assign QString to int";
3141     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3142     o->setProperty("assignWrongTypeToValueType", true);
3143
3144     delete o;
3145 }
3146
3147 void tst_qdeclarativeecmascript::eval()
3148 {
3149     QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3150
3151     QObject *o = component.create();
3152     QVERIFY(o != 0);
3153
3154     QCOMPARE(o->property("test1").toBool(), true);
3155     QCOMPARE(o->property("test2").toBool(), true);
3156     QCOMPARE(o->property("test3").toBool(), true);
3157     QCOMPARE(o->property("test4").toBool(), true);
3158     QCOMPARE(o->property("test5").toBool(), true);
3159
3160     delete o;
3161 }
3162
3163 void tst_qdeclarativeecmascript::function()
3164 {
3165     QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3166
3167     QObject *o = component.create();
3168     QVERIFY(o != 0);
3169
3170     QCOMPARE(o->property("test1").toBool(), true);
3171     QCOMPARE(o->property("test2").toBool(), true);
3172     QCOMPARE(o->property("test3").toBool(), true);
3173
3174     delete o;
3175 }
3176
3177 // Test the "Qt.include" method
3178 void tst_qdeclarativeecmascript::include()
3179 {
3180     // Non-library relative include
3181     {
3182     QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3183     QObject *o = component.create();
3184     QVERIFY(o != 0);
3185
3186     QCOMPARE(o->property("test0").toInt(), 99);
3187     QCOMPARE(o->property("test1").toBool(), true);
3188     QCOMPARE(o->property("test2").toBool(), true);
3189     QCOMPARE(o->property("test2_1").toBool(), true);
3190     QCOMPARE(o->property("test3").toBool(), true);
3191     QCOMPARE(o->property("test3_1").toBool(), true);
3192
3193     delete o;
3194     }
3195
3196     // Library relative include
3197     {
3198     QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3199     QObject *o = component.create();
3200     QVERIFY(o != 0);
3201
3202     QCOMPARE(o->property("test0").toInt(), 99);
3203     QCOMPARE(o->property("test1").toBool(), true);
3204     QCOMPARE(o->property("test2").toBool(), true);
3205     QCOMPARE(o->property("test2_1").toBool(), true);
3206     QCOMPARE(o->property("test3").toBool(), true);
3207     QCOMPARE(o->property("test3_1").toBool(), true);
3208
3209     delete o;
3210     }
3211
3212     // Callback
3213     {
3214     QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3215     QObject *o = component.create();
3216     QVERIFY(o != 0);
3217
3218     QCOMPARE(o->property("test1").toBool(), true);
3219     QCOMPARE(o->property("test2").toBool(), true);
3220     QCOMPARE(o->property("test3").toBool(), true);
3221     QCOMPARE(o->property("test4").toBool(), true);
3222     QCOMPARE(o->property("test5").toBool(), true);
3223     QCOMPARE(o->property("test6").toBool(), true);
3224
3225     delete o;
3226     }
3227
3228     // Including file with ".pragma library"
3229     {
3230     QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3231     QObject *o = component.create();
3232     QVERIFY(o != 0);
3233     QCOMPARE(o->property("test1").toInt(), 100);
3234
3235     delete o;
3236     }
3237
3238     // Remote - success
3239     {
3240     TestHTTPServer server(8111);
3241     QVERIFY(server.isValid());
3242     server.serveDirectory(SRCDIR "/data");
3243
3244     QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3245     QObject *o = component.create();
3246     QVERIFY(o != 0);
3247
3248     QTRY_VERIFY(o->property("done").toBool() == true);
3249     QTRY_VERIFY(o->property("done2").toBool() == true);
3250
3251     QCOMPARE(o->property("test1").toBool(), true);
3252     QCOMPARE(o->property("test2").toBool(), true);
3253     QCOMPARE(o->property("test3").toBool(), true);
3254     QCOMPARE(o->property("test4").toBool(), true);
3255     QCOMPARE(o->property("test5").toBool(), true);
3256
3257     QCOMPARE(o->property("test6").toBool(), true);
3258     QCOMPARE(o->property("test7").toBool(), true);
3259     QCOMPARE(o->property("test8").toBool(), true);
3260     QCOMPARE(o->property("test9").toBool(), true);
3261     QCOMPARE(o->property("test10").toBool(), true);
3262
3263     delete o;
3264     }
3265
3266     // Remote - error
3267     {
3268     TestHTTPServer server(8111);
3269     QVERIFY(server.isValid());
3270     server.serveDirectory(SRCDIR "/data");
3271
3272     QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3273     QObject *o = component.create();
3274     QVERIFY(o != 0);
3275
3276     QTRY_VERIFY(o->property("done").toBool() == true);
3277
3278     QCOMPARE(o->property("test1").toBool(), true);
3279     QCOMPARE(o->property("test2").toBool(), true);
3280     QCOMPARE(o->property("test3").toBool(), true);
3281
3282     delete o;
3283     }
3284 }
3285
3286 void tst_qdeclarativeecmascript::qtbug_10696()
3287 {
3288     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3289     QObject *o = component.create();
3290     QVERIFY(o != 0);
3291     delete o;
3292 }
3293
3294 void tst_qdeclarativeecmascript::qtbug_11606()
3295 {
3296     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3297     QObject *o = component.create();
3298     QVERIFY(o != 0);
3299     QCOMPARE(o->property("test").toBool(), true);
3300     delete o;
3301 }
3302
3303 void tst_qdeclarativeecmascript::qtbug_11600()
3304 {
3305     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3306     QObject *o = component.create();
3307     QVERIFY(o != 0);
3308     QCOMPARE(o->property("test").toBool(), true);
3309     delete o;
3310 }
3311
3312 // Reading and writing non-scriptable properties should fail
3313 void tst_qdeclarativeecmascript::nonscriptable()
3314 {
3315     QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3316     QObject *o = component.create();
3317     QVERIFY(o != 0);
3318     QCOMPARE(o->property("readOk").toBool(), true);
3319     QCOMPARE(o->property("writeOk").toBool(), true);
3320     delete o;
3321 }
3322
3323 // deleteLater() should not be callable from QML
3324 void tst_qdeclarativeecmascript::deleteLater()
3325 {
3326     QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3327     QObject *o = component.create();
3328     QVERIFY(o != 0);
3329     QCOMPARE(o->property("test").toBool(), true);
3330     delete o;
3331 }
3332
3333 void tst_qdeclarativeecmascript::in()
3334 {
3335     QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3336     QObject *o = component.create();
3337     QVERIFY(o != 0);
3338     QCOMPARE(o->property("test1").toBool(), true);
3339     QCOMPARE(o->property("test2").toBool(), true);
3340     delete o;
3341 }
3342
3343 void tst_qdeclarativeecmascript::sharedAttachedObject()
3344 {
3345     QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3346     QObject *o = component.create();
3347     QVERIFY(o != 0);
3348     QCOMPARE(o->property("test1").toBool(), true);
3349     QCOMPARE(o->property("test2").toBool(), true);
3350     delete o;
3351 }
3352
3353 // QTBUG-13999
3354 void tst_qdeclarativeecmascript::objectName()
3355 {
3356     QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3357     QObject *o = component.create();
3358     QVERIFY(o != 0);
3359
3360     QCOMPARE(o->property("test1").toString(), QString("hello"));
3361     QCOMPARE(o->property("test2").toString(), QString("ell"));
3362
3363     o->setObjectName("world");
3364
3365     QCOMPARE(o->property("test1").toString(), QString("world"));
3366     QCOMPARE(o->property("test2").toString(), QString("orl"));
3367
3368     delete o;
3369 }
3370
3371 void tst_qdeclarativeecmascript::writeRemovesBinding()
3372 {
3373     QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3374     QObject *o = component.create();
3375     QVERIFY(o != 0);
3376
3377     QCOMPARE(o->property("test").toBool(), true);
3378
3379     delete o;
3380 }
3381
3382 // Test bindings assigned to alias properties actually assign to the alias' target
3383 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3384 {
3385     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3386     QObject *o = component.create();
3387     QVERIFY(o != 0);
3388
3389     QCOMPARE(o->property("test").toBool(), true);
3390
3391     delete o;
3392 }
3393
3394 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3395 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3396 {
3397     { 
3398     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3399     QObject *o = component.create();
3400     QVERIFY(o != 0);
3401
3402     QCOMPARE(o->property("test").toBool(), true);
3403
3404     delete o;
3405     }
3406
3407     {
3408     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
3409     QObject *o = component.create();
3410     QVERIFY(o != 0);
3411
3412     QCOMPARE(o->property("test").toBool(), true);
3413
3414     delete o;
3415     }
3416
3417     {
3418     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
3419     QObject *o = component.create();
3420     QVERIFY(o != 0);
3421
3422     QCOMPARE(o->property("test").toBool(), true);
3423
3424     delete o;
3425     }
3426 }
3427
3428 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
3429 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
3430 {
3431     {
3432     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
3433     QObject *o = component.create();
3434     QVERIFY(o != 0);
3435
3436     QCOMPARE(o->property("test").toBool(), true);
3437
3438     delete o;
3439     }
3440
3441     {
3442     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
3443     QObject *o = component.create();
3444     QVERIFY(o != 0);
3445
3446     QCOMPARE(o->property("test").toBool(), true);
3447
3448     delete o;
3449     }
3450
3451     {
3452     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
3453     QObject *o = component.create();
3454     QVERIFY(o != 0);
3455
3456     QCOMPARE(o->property("test").toBool(), true);
3457
3458     delete o;
3459     }
3460 }
3461
3462 void tst_qdeclarativeecmascript::revisionErrors()
3463 {
3464     {
3465         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
3466         QString url = component.url().toString();
3467
3468         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3469         QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
3470         QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
3471
3472         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3473         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3474         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3475         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3476         QVERIFY(object != 0);
3477         delete object;
3478     }
3479     {
3480         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
3481         QString url = component.url().toString();
3482
3483         // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
3484         // method2, prop2 from MyRevisionedClass not available
3485         // method4, prop4 from MyRevisionedSubclass not available
3486         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3487         QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
3488         QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
3489         QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
3490         QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
3491
3492         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3493         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3494         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3495         QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
3496         QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
3497         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3498         QVERIFY(object != 0);
3499         delete object;
3500     }
3501     {
3502         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
3503         QString url = component.url().toString();
3504
3505         // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
3506         // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
3507         QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
3508         QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
3509         QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
3510         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3511         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3512         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3513         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3514         QVERIFY(object != 0);
3515         delete object;
3516     }
3517 }
3518
3519 void tst_qdeclarativeecmascript::revision()
3520 {
3521     {
3522         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
3523         QString url = component.url().toString();
3524
3525         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3526         QVERIFY(object != 0);
3527         delete object;
3528     }
3529     {
3530         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
3531         QString url = component.url().toString();
3532
3533         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3534         QVERIFY(object != 0);
3535         delete object;
3536     }
3537     {
3538         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
3539         QString url = component.url().toString();
3540
3541         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3542         QVERIFY(object != 0);
3543         delete object;
3544     }
3545     // Test that non-root classes can resolve revisioned methods
3546     {
3547         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
3548
3549         QObject *object = component.create();
3550         QVERIFY(object != 0);
3551         QCOMPARE(object->property("test").toReal(), 11.);
3552         delete object;
3553     }
3554 }
3555
3556 // Test for QScriptDeclarativeClass::pushCleanContext()
3557 void tst_qdeclarativeecmascript::pushCleanContext()
3558 {
3559     QScriptEngine engine;
3560     engine.globalObject().setProperty("a", 6);
3561     QCOMPARE(engine.evaluate("a").toInt32(), 6);
3562
3563     // First confirm pushContext() behaves as we expect
3564     QScriptValue object = engine.newObject();
3565     object.setProperty("a", 15);
3566     QScriptContext *context1 = engine.pushContext();
3567     context1->pushScope(object);
3568     QCOMPARE(engine.evaluate("a").toInt32(), 15);
3569
3570     QScriptContext *context2 = engine.pushContext();
3571     Q_UNUSED(context2);
3572     QCOMPARE(engine.evaluate("a").toInt32(), 15);
3573     QScriptValue func1 = engine.evaluate("(function() { return a; })");
3574
3575     // Now check that pushCleanContext() works
3576     QScriptDeclarativeClass::pushCleanContext(&engine);
3577     QCOMPARE(engine.evaluate("a").toInt32(), 6);
3578     QScriptValue func2 = engine.evaluate("(function() { return a; })");
3579
3580     engine.popContext();
3581     QCOMPARE(engine.evaluate("a").toInt32(), 15);
3582
3583     engine.popContext();
3584     QCOMPARE(engine.evaluate("a").toInt32(), 15);
3585
3586     engine.popContext();
3587     QCOMPARE(engine.evaluate("a").toInt32(), 6);
3588
3589     // Check that function objects created in these contexts work
3590     QCOMPARE(func1.call().toInt32(), 15);
3591     QCOMPARE(func2.call().toInt32(), 6);
3592 }
3593
3594 void tst_qdeclarativeecmascript::realToInt()
3595 {
3596     QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
3597     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
3598     QVERIFY(object != 0);
3599
3600     QMetaObject::invokeMethod(object, "test1");
3601     QCOMPARE(object->value(), int(4));
3602     QMetaObject::invokeMethod(object, "test2");
3603     QCOMPARE(object->value(), int(8));
3604 }
3605
3606 QTEST_MAIN(tst_qdeclarativeecmascript)
3607
3608 #include "tst_qdeclarativeecmascript.moc"