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     QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
2575     QObject *object = component.create();
2576     QVERIFY(object != 0);
2577     QCOMPARE(object->property("existingUriTest").toInt(), 20);
2578     QCOMPARE(object->property("scriptTest").toInt(), 13);
2579     QCOMPARE(object->property("qobjectTest").toInt(), 20);
2580     QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
2581     QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
2582     QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
2583     QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
2584     delete object;
2585
2586     // test that caching of module apis works correctly.
2587     QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
2588     object = componentTwo.create();
2589     QVERIFY(object != 0);
2590     QCOMPARE(object->property("existingUriTest").toInt(), 20);
2591     QCOMPARE(object->property("scriptTest").toInt(), 13);            // shouldn't have incremented.
2592     QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);   // shouldn't have incremented.
2593     delete object;
2594
2595     // test that writing to a property of module apis works correctly.
2596     QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
2597     QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
2598     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2599     object = componentThree.create();
2600     QVERIFY(object != 0);
2601     QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2602     QCOMPARE(object->property("writableProperty").toInt(), 50);
2603     QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
2604     QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
2605     QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2606     QCOMPARE(object->property("writableProperty").toInt(), 30);
2607     delete object;
2608
2609     QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
2610     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2611     object = failOne.create();
2612     QVERIFY(object == 0); // should have failed: invalid major version
2613
2614     QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
2615     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2616     object = failTwo.create();
2617     QVERIFY(object == 0); // should have failed: invalid minor version
2618 }
2619
2620 void tst_qdeclarativeecmascript::importScripts()
2621 {
2622     QObject *object = 0;
2623
2624     // first, ensure that the required behaviour works.
2625     QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2626     object = component.create();
2627     QVERIFY(object != 0);
2628     QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2629     QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2630     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2631     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2632     delete object;
2633
2634     QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2635     object = componentTwo.create();
2636     QVERIFY(object != 0);
2637     QCOMPARE(object->property("componentError"), QVariant(5));
2638     delete object;
2639
2640     // then, ensure that unintended behaviour does not work.
2641     QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2642     QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Result of expression 'TestScriptImport.ImportOneJs' [undefined] is not an object.");
2643     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2644     object = failOneComponent.create();
2645     QVERIFY(object != 0);
2646     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2647     delete object;
2648     QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2649     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2650     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2651     object = failTwoComponent.create();
2652     QVERIFY(object != 0);
2653     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2654     delete object;
2655     QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2656     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Result of expression 'testQtObject.TestModuleImport.JsQtTest' [undefined] is not an object.");
2657     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2658     object = failThreeComponent.create();
2659     QVERIFY(object != 0);
2660     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2661     delete object;
2662     QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2663     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2664     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2665     object = failFourComponent.create();
2666     QVERIFY(object != 0);
2667     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2668     delete object;
2669     QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2670     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2671     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2672     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2673     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2674     object = failFiveComponent.create();
2675     QVERIFY(object != 0);
2676     QCOMPARE(object->property("componentError"), QVariant(0));
2677     delete object;
2678
2679     // also, test that importing scripts with .pragma library works as required
2680     QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2681     object = pragmaLibraryComponent.create();
2682     QVERIFY(object != 0);
2683     QCOMPARE(object->property("testValue"), QVariant(31));
2684     delete object;
2685
2686     // and that .pragma library scripts don't inherit imports from any .qml file
2687     QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2688     object = pragmaLibraryComponentTwo.create();
2689     QVERIFY(object != 0);
2690     QCOMPARE(object->property("testValue"), QVariant(0));
2691     delete object;
2692 }
2693
2694 void tst_qdeclarativeecmascript::scarceResources()
2695 {
2696     QPixmap origPixmap(100, 100);
2697     origPixmap.fill(Qt::blue);
2698
2699     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2700     ScarceResourceObject *eo = 0;
2701     QObject *object = 0;
2702
2703     // in the following three cases, the instance created from the component
2704     // has a property which is a copy of the scarce resource; hence, the
2705     // resource should NOT be detached prior to deletion of the object instance,
2706     // unless the resource is destroyed explicitly.
2707     QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2708     object = component.create();
2709     QVERIFY(object != 0);
2710     QVERIFY(object->property("scarceResourceCopy").isValid());
2711     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2712     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2713     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2714     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2715     delete object;
2716
2717     QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2718     object = componentTwo.create();
2719     QVERIFY(object != 0);
2720     QVERIFY(object->property("scarceResourceCopy").isValid());
2721     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2722     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2723     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2724     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2725     delete object;
2726
2727     QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
2728     object = componentThree.create();
2729     QVERIFY(object != 0);
2730     QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
2731     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2732     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2733     QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
2734     delete object;
2735
2736     // in the following three cases, no other copy should exist in memory,
2737     // and so it should be detached (unless explicitly preserved).
2738     QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
2739     object = componentFour.create();
2740     QVERIFY(object != 0);
2741     QVERIFY(object->property("scarceResourceTest").isValid());
2742     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2743     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2744     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2745     QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
2746     delete object;
2747
2748     QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
2749     object = componentFive.create();
2750     QVERIFY(object != 0);
2751     QVERIFY(object->property("scarceResourceTest").isValid());
2752     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2753     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2754     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2755     QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
2756     delete object;
2757
2758     QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
2759     object = componentSix.create();
2760     QVERIFY(object != 0);
2761     QVERIFY(object->property("scarceResourceTest").isValid());
2762     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2763     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2764     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2765     QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
2766     delete object;
2767
2768     // test that scarce resources are handled correctly for imports
2769     QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
2770     object = componentSeven.create();
2771     QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
2772     QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
2773     delete object;
2774
2775     QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
2776     object = componentEight.create();
2777     QVERIFY(object != 0);
2778     QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
2779     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2780     delete object;
2781
2782     QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
2783     object = componentNine.create();
2784     QVERIFY(object != 0);
2785     QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
2786     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2787     QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
2788     QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
2789     QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
2790     QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
2791     delete object;
2792
2793     // test that scarce resources are handled properly in signal invocation
2794     QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
2795     object = componentTen.create();
2796     QVERIFY(object != 0);
2797     QObject *srsc = object->findChild<QObject*>("srsc");
2798     QVERIFY(srsc);
2799     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
2800     QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
2801     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2802     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2803     QMetaObject::invokeMethod(srsc, "testSignal");
2804     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
2805     QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
2806     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2807     QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
2808     QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
2809     QVERIFY(srsc->property("scarceResourceCopy").isValid());
2810     QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2811     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2812     QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
2813     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2814     delete object;
2815
2816     // test that scarce resources are handled properly from js functions in qml files
2817     QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
2818     object = componentEleven.create();
2819     QVERIFY(object != 0);
2820     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2821     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2822     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2823     QMetaObject::invokeMethod(object, "retrieveScarceResource");
2824     QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
2825     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2826     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2827     QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
2828     QMetaObject::invokeMethod(object, "releaseScarceResource");
2829     QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
2830     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2831     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2832     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2833     delete object;
2834
2835     // test that if an exception occurs while invoking js function from cpp, that the resources are released.
2836     QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
2837     object = componentTwelve.create();
2838     QVERIFY(object != 0);
2839     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2840     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2841     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2842     QString srp_name = object->property("srp_name").toString();
2843     QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
2844     QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
2845     QMetaObject::invokeMethod(object, "retrieveScarceResource");
2846     QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
2847     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2848     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2849     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2850     delete object;
2851 }
2852
2853 void tst_qdeclarativeecmascript::propertyChangeSlots()
2854 {
2855     // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
2856     QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
2857     QObject *object = component.create();
2858     QVERIFY(object != 0);
2859     delete object;
2860
2861     // ensure that invalid property names fail properly.
2862     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2863     QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
2864     QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
2865     QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
2866     object = e1.create();
2867     QVERIFY(object == 0);
2868     delete object;
2869
2870     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2871     QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
2872     expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
2873     QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
2874     object = e2.create();
2875     QVERIFY(object == 0);
2876     delete object;
2877
2878     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2879     QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
2880     expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
2881     QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
2882     object = e3.create();
2883     QVERIFY(object == 0);
2884     delete object;
2885
2886     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2887     QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
2888     expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
2889     QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
2890     object = e4.create();
2891     QVERIFY(object == 0);
2892     delete object;
2893 }
2894
2895 // Test that assigning a null object works 
2896 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
2897 void tst_qdeclarativeecmascript::nullObjectBinding()
2898 {
2899     QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
2900
2901     QObject *object = component.create();
2902     QVERIFY(object != 0);
2903
2904     QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
2905
2906     delete object;
2907 }
2908
2909 // Test that bindings don't evaluate once the engine has been destroyed
2910 void tst_qdeclarativeecmascript::deletedEngine()
2911 {
2912     QDeclarativeEngine *engine = new QDeclarativeEngine;
2913     QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
2914
2915     QObject *object = component.create();
2916     QVERIFY(object != 0);
2917
2918     QCOMPARE(object->property("a").toInt(), 39);
2919     object->setProperty("b", QVariant(9));
2920     QCOMPARE(object->property("a").toInt(), 117);
2921
2922     delete engine;
2923
2924     QCOMPARE(object->property("a").toInt(), 117);
2925     object->setProperty("b", QVariant(10));
2926     QCOMPARE(object->property("a").toInt(), 117);
2927
2928     delete object;
2929 }
2930
2931 // Test the crashing part of QTBUG-9705
2932 void tst_qdeclarativeecmascript::libraryScriptAssert()
2933 {
2934     QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
2935
2936     QObject *object = component.create();
2937     QVERIFY(object != 0);
2938
2939     delete object;
2940 }
2941
2942 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
2943 {
2944     QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
2945
2946     QObject *object = component.create();
2947     QVERIFY(object != 0);
2948
2949     QCOMPARE(object->property("test1").toInt(), 10);
2950     QCOMPARE(object->property("test2").toInt(), 11);
2951
2952     object->setProperty("runTest", true);
2953
2954     QCOMPARE(object->property("test1"), QVariant());
2955     QCOMPARE(object->property("test2"), QVariant());
2956
2957
2958     delete object;
2959 }
2960
2961 void tst_qdeclarativeecmascript::qtbug_9792()
2962 {
2963     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
2964
2965     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2966
2967     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
2968     QVERIFY(object != 0);
2969
2970     QTest::ignoreMessage(QtDebugMsg, "Hello world!");
2971     object->basicSignal();
2972
2973     delete context;
2974
2975     transientErrorsMsgCount = 0;
2976     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
2977
2978     object->basicSignal();
2979     
2980     qInstallMsgHandler(old);
2981
2982     QCOMPARE(transientErrorsMsgCount, 0);
2983
2984     delete object;
2985 }
2986
2987 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
2988 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
2989 {
2990     QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
2991
2992     QObject *o = component.create();
2993     QVERIFY(o != 0);
2994
2995     QObject *nested = qvariant_cast<QObject *>(o->property("object"));
2996     QVERIFY(nested != 0);
2997
2998     QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
2999
3000     delete nested;
3001     nested = qvariant_cast<QObject *>(o->property("object"));
3002     QVERIFY(nested == 0);
3003
3004     // If the bug is present, the next line will crash
3005     delete o;
3006 }
3007
3008 // Test that we shut down without stupid warnings
3009 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3010 {
3011     {
3012     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3013
3014     QObject *o = component.create();
3015
3016     transientErrorsMsgCount = 0;
3017     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3018
3019     delete o;
3020
3021     qInstallMsgHandler(old);
3022
3023     QCOMPARE(transientErrorsMsgCount, 0);
3024     }
3025
3026
3027     {
3028     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3029
3030     QObject *o = component.create();
3031
3032     transientErrorsMsgCount = 0;
3033     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3034
3035     delete o;
3036
3037     qInstallMsgHandler(old);
3038
3039     QCOMPARE(transientErrorsMsgCount, 0);
3040     }
3041 }
3042
3043 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3044 {
3045     {
3046     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3047
3048     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3049     QVERIFY(o != 0);
3050
3051     QVERIFY(o->objectProperty() != 0);
3052
3053     o->setProperty("runTest", true);
3054
3055     QVERIFY(o->objectProperty() == 0);
3056
3057     delete o;
3058     }
3059
3060     {
3061     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3062
3063     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3064     QVERIFY(o != 0);
3065
3066     QVERIFY(o->objectProperty() == 0);
3067
3068     delete o;
3069     }
3070 }
3071
3072 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3073 {
3074     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3075
3076     QString url = component.url().toString();
3077     QString warning = url + ":4: Unable to assign a function to a property.";
3078     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3079     
3080     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3081     QVERIFY(o != 0);
3082
3083     QVERIFY(!o->property("a").isValid());
3084
3085     delete o;
3086 }
3087
3088 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3089 {
3090     QFETCH(QString, triggerProperty);
3091
3092     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3093     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3094
3095     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3096     QVERIFY(o != 0);
3097     QVERIFY(!o->property("a").isValid());
3098
3099     o->setProperty("aNumber", QVariant(5));
3100     o->setProperty(triggerProperty.toUtf8().constData(), true);
3101     QCOMPARE(o->property("a"), QVariant(50));
3102
3103     o->setProperty("aNumber", QVariant(10));
3104     QCOMPARE(o->property("a"), QVariant(100));
3105
3106     delete o;
3107 }
3108
3109 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3110 {
3111     QTest::addColumn<QString>("triggerProperty");
3112
3113     QTest::newRow("assign to property") << "assignToProperty";
3114     QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3115
3116     QTest::newRow("assign to value type") << "assignToValueType";
3117
3118     QTest::newRow("use 'this'") << "assignWithThis";
3119     QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3120 }
3121
3122 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3123 {
3124     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3125     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3126
3127     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3128     QVERIFY(o != 0);
3129     QVERIFY(!o->property("a").isValid());
3130
3131     o->setProperty("assignFuncWithoutReturn", true);
3132     QVERIFY(!o->property("a").isValid());
3133
3134     QString url = component.url().toString();
3135     QString warning = url + ":67: Unable to assign QString to int";
3136     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3137     o->setProperty("assignWrongType", true);
3138
3139     warning = url + ":71: Unable to assign QString to int";
3140     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3141     o->setProperty("assignWrongTypeToValueType", true);
3142
3143     delete o;
3144 }
3145
3146 void tst_qdeclarativeecmascript::eval()
3147 {
3148     QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3149
3150     QObject *o = component.create();
3151     QVERIFY(o != 0);
3152
3153     QCOMPARE(o->property("test1").toBool(), true);
3154     QCOMPARE(o->property("test2").toBool(), true);
3155     QCOMPARE(o->property("test3").toBool(), true);
3156     QCOMPARE(o->property("test4").toBool(), true);
3157     QCOMPARE(o->property("test5").toBool(), true);
3158
3159     delete o;
3160 }
3161
3162 void tst_qdeclarativeecmascript::function()
3163 {
3164     QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3165
3166     QObject *o = component.create();
3167     QVERIFY(o != 0);
3168
3169     QCOMPARE(o->property("test1").toBool(), true);
3170     QCOMPARE(o->property("test2").toBool(), true);
3171     QCOMPARE(o->property("test3").toBool(), true);
3172
3173     delete o;
3174 }
3175
3176 // Test the "Qt.include" method
3177 void tst_qdeclarativeecmascript::include()
3178 {
3179     // Non-library relative include
3180     {
3181     QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3182     QObject *o = component.create();
3183     QVERIFY(o != 0);
3184
3185     QCOMPARE(o->property("test0").toInt(), 99);
3186     QCOMPARE(o->property("test1").toBool(), true);
3187     QCOMPARE(o->property("test2").toBool(), true);
3188     QCOMPARE(o->property("test2_1").toBool(), true);
3189     QCOMPARE(o->property("test3").toBool(), true);
3190     QCOMPARE(o->property("test3_1").toBool(), true);
3191
3192     delete o;
3193     }
3194
3195     // Library relative include
3196     {
3197     QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3198     QObject *o = component.create();
3199     QVERIFY(o != 0);
3200
3201     QCOMPARE(o->property("test0").toInt(), 99);
3202     QCOMPARE(o->property("test1").toBool(), true);
3203     QCOMPARE(o->property("test2").toBool(), true);
3204     QCOMPARE(o->property("test2_1").toBool(), true);
3205     QCOMPARE(o->property("test3").toBool(), true);
3206     QCOMPARE(o->property("test3_1").toBool(), true);
3207
3208     delete o;
3209     }
3210
3211     // Callback
3212     {
3213     QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3214     QObject *o = component.create();
3215     QVERIFY(o != 0);
3216
3217     QCOMPARE(o->property("test1").toBool(), true);
3218     QCOMPARE(o->property("test2").toBool(), true);
3219     QCOMPARE(o->property("test3").toBool(), true);
3220     QCOMPARE(o->property("test4").toBool(), true);
3221     QCOMPARE(o->property("test5").toBool(), true);
3222     QCOMPARE(o->property("test6").toBool(), true);
3223
3224     delete o;
3225     }
3226
3227     // Including file with ".pragma library"
3228     {
3229     QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3230     QObject *o = component.create();
3231     QVERIFY(o != 0);
3232     QCOMPARE(o->property("test1").toInt(), 100);
3233
3234     delete o;
3235     }
3236
3237     // Remote - success
3238     {
3239     TestHTTPServer server(8111);
3240     QVERIFY(server.isValid());
3241     server.serveDirectory(SRCDIR "/data");
3242
3243     QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3244     QObject *o = component.create();
3245     QVERIFY(o != 0);
3246
3247     QTRY_VERIFY(o->property("done").toBool() == true);
3248     QTRY_VERIFY(o->property("done2").toBool() == true);
3249
3250     QCOMPARE(o->property("test1").toBool(), true);
3251     QCOMPARE(o->property("test2").toBool(), true);
3252     QCOMPARE(o->property("test3").toBool(), true);
3253     QCOMPARE(o->property("test4").toBool(), true);
3254     QCOMPARE(o->property("test5").toBool(), true);
3255
3256     QCOMPARE(o->property("test6").toBool(), true);
3257     QCOMPARE(o->property("test7").toBool(), true);
3258     QCOMPARE(o->property("test8").toBool(), true);
3259     QCOMPARE(o->property("test9").toBool(), true);
3260     QCOMPARE(o->property("test10").toBool(), true);
3261
3262     delete o;
3263     }
3264
3265     // Remote - error
3266     {
3267     TestHTTPServer server(8111);
3268     QVERIFY(server.isValid());
3269     server.serveDirectory(SRCDIR "/data");
3270
3271     QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3272     QObject *o = component.create();
3273     QVERIFY(o != 0);
3274
3275     QTRY_VERIFY(o->property("done").toBool() == true);
3276
3277     QCOMPARE(o->property("test1").toBool(), true);
3278     QCOMPARE(o->property("test2").toBool(), true);
3279     QCOMPARE(o->property("test3").toBool(), true);
3280
3281     delete o;
3282     }
3283 }
3284
3285 void tst_qdeclarativeecmascript::qtbug_10696()
3286 {
3287     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3288     QObject *o = component.create();
3289     QVERIFY(o != 0);
3290     delete o;
3291 }
3292
3293 void tst_qdeclarativeecmascript::qtbug_11606()
3294 {
3295     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3296     QObject *o = component.create();
3297     QVERIFY(o != 0);
3298     QCOMPARE(o->property("test").toBool(), true);
3299     delete o;
3300 }
3301
3302 void tst_qdeclarativeecmascript::qtbug_11600()
3303 {
3304     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3305     QObject *o = component.create();
3306     QVERIFY(o != 0);
3307     QCOMPARE(o->property("test").toBool(), true);
3308     delete o;
3309 }
3310
3311 // Reading and writing non-scriptable properties should fail
3312 void tst_qdeclarativeecmascript::nonscriptable()
3313 {
3314     QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3315     QObject *o = component.create();
3316     QVERIFY(o != 0);
3317     QCOMPARE(o->property("readOk").toBool(), true);
3318     QCOMPARE(o->property("writeOk").toBool(), true);
3319     delete o;
3320 }
3321
3322 // deleteLater() should not be callable from QML
3323 void tst_qdeclarativeecmascript::deleteLater()
3324 {
3325     QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3326     QObject *o = component.create();
3327     QVERIFY(o != 0);
3328     QCOMPARE(o->property("test").toBool(), true);
3329     delete o;
3330 }
3331
3332 void tst_qdeclarativeecmascript::in()
3333 {
3334     QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3335     QObject *o = component.create();
3336     QVERIFY(o != 0);
3337     QCOMPARE(o->property("test1").toBool(), true);
3338     QCOMPARE(o->property("test2").toBool(), true);
3339     delete o;
3340 }
3341
3342 void tst_qdeclarativeecmascript::sharedAttachedObject()
3343 {
3344     QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3345     QObject *o = component.create();
3346     QVERIFY(o != 0);
3347     QCOMPARE(o->property("test1").toBool(), true);
3348     QCOMPARE(o->property("test2").toBool(), true);
3349     delete o;
3350 }
3351
3352 // QTBUG-13999
3353 void tst_qdeclarativeecmascript::objectName()
3354 {
3355     QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3356     QObject *o = component.create();
3357     QVERIFY(o != 0);
3358
3359     QCOMPARE(o->property("test1").toString(), QString("hello"));
3360     QCOMPARE(o->property("test2").toString(), QString("ell"));
3361
3362     o->setObjectName("world");
3363
3364     QCOMPARE(o->property("test1").toString(), QString("world"));
3365     QCOMPARE(o->property("test2").toString(), QString("orl"));
3366
3367     delete o;
3368 }
3369
3370 void tst_qdeclarativeecmascript::writeRemovesBinding()
3371 {
3372     QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3373     QObject *o = component.create();
3374     QVERIFY(o != 0);
3375
3376     QCOMPARE(o->property("test").toBool(), true);
3377
3378     delete o;
3379 }
3380
3381 // Test bindings assigned to alias properties actually assign to the alias' target
3382 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3383 {
3384     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3385     QObject *o = component.create();
3386     QVERIFY(o != 0);
3387
3388     QCOMPARE(o->property("test").toBool(), true);
3389
3390     delete o;
3391 }
3392
3393 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3394 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3395 {
3396     { 
3397     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3398     QObject *o = component.create();
3399     QVERIFY(o != 0);
3400
3401     QCOMPARE(o->property("test").toBool(), true);
3402
3403     delete o;
3404     }
3405
3406     {
3407     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
3408     QObject *o = component.create();
3409     QVERIFY(o != 0);
3410
3411     QCOMPARE(o->property("test").toBool(), true);
3412
3413     delete o;
3414     }
3415
3416     {
3417     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
3418     QObject *o = component.create();
3419     QVERIFY(o != 0);
3420
3421     QCOMPARE(o->property("test").toBool(), true);
3422
3423     delete o;
3424     }
3425 }
3426
3427 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
3428 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
3429 {
3430     {
3431     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
3432     QObject *o = component.create();
3433     QVERIFY(o != 0);
3434
3435     QCOMPARE(o->property("test").toBool(), true);
3436
3437     delete o;
3438     }
3439
3440     {
3441     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
3442     QObject *o = component.create();
3443     QVERIFY(o != 0);
3444
3445     QCOMPARE(o->property("test").toBool(), true);
3446
3447     delete o;
3448     }
3449
3450     {
3451     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
3452     QObject *o = component.create();
3453     QVERIFY(o != 0);
3454
3455     QCOMPARE(o->property("test").toBool(), true);
3456
3457     delete o;
3458     }
3459 }
3460
3461 void tst_qdeclarativeecmascript::revisionErrors()
3462 {
3463     {
3464         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
3465         QString url = component.url().toString();
3466
3467         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3468         QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
3469         QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
3470
3471         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3472         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3473         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3474         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3475         QVERIFY(object != 0);
3476         delete object;
3477     }
3478     {
3479         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
3480         QString url = component.url().toString();
3481
3482         // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
3483         // method2, prop2 from MyRevisionedClass not available
3484         // method4, prop4 from MyRevisionedSubclass not available
3485         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3486         QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
3487         QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
3488         QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
3489         QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
3490
3491         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3492         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3493         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3494         QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
3495         QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
3496         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3497         QVERIFY(object != 0);
3498         delete object;
3499     }
3500     {
3501         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
3502         QString url = component.url().toString();
3503
3504         // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
3505         // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
3506         QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
3507         QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
3508         QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
3509         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3510         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3511         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3512         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3513         QVERIFY(object != 0);
3514         delete object;
3515     }
3516 }
3517
3518 void tst_qdeclarativeecmascript::revision()
3519 {
3520     {
3521         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
3522         QString url = component.url().toString();
3523
3524         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3525         QVERIFY(object != 0);
3526         delete object;
3527     }
3528     {
3529         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
3530         QString url = component.url().toString();
3531
3532         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3533         QVERIFY(object != 0);
3534         delete object;
3535     }
3536     {
3537         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
3538         QString url = component.url().toString();
3539
3540         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3541         QVERIFY(object != 0);
3542         delete object;
3543     }
3544     // Test that non-root classes can resolve revisioned methods
3545     {
3546         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
3547
3548         QObject *object = component.create();
3549         QVERIFY(object != 0);
3550         QCOMPARE(object->property("test").toReal(), 11.);
3551         delete object;
3552     }
3553 }
3554
3555 void tst_qdeclarativeecmascript::realToInt()
3556 {
3557     QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
3558     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
3559     QVERIFY(object != 0);
3560
3561     QMetaObject::invokeMethod(object, "test1");
3562     QCOMPARE(object->value(), int(4));
3563     QMetaObject::invokeMethod(object, "test2");
3564     QCOMPARE(object->value(), int(8));
3565 }
3566
3567 QTEST_MAIN(tst_qdeclarativeecmascript)
3568
3569 #include "tst_qdeclarativeecmascript.moc"