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