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