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