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