Merge the QJSEngine and QJSValue development branch into master.
[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 "testtypes.h"
53 #include "testhttpserver.h"
54 #include "../../../shared/util.h"
55
56 #ifdef Q_OS_SYMBIAN
57 // In Symbian OS test data is located in applications private dir
58 #define SRCDIR "."
59 #endif
60
61 /*
62 This test covers evaluation of ECMAScript expressions and bindings from within
63 QML.  This does not include static QML language issues.
64
65 Static QML language issues are covered in qmllanguage
66 */
67 inline QUrl TEST_FILE(const QString &filename)
68 {
69     QFileInfo fileInfo(__FILE__);
70     return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
71 }
72
73 inline QUrl TEST_FILE(const char *filename)
74 {
75     return TEST_FILE(QLatin1String(filename));
76 }
77
78 class tst_qdeclarativeecmascript : public QObject
79 {
80     Q_OBJECT
81 public:
82     tst_qdeclarativeecmascript() {}
83
84 private slots:
85     void initTestCase();
86     void assignBasicTypes();
87     void idShortcutInvalidates();
88     void boolPropertiesEvaluateAsBool();
89     void methods();
90     void signalAssignment();
91     void bindingLoop();
92     void basicExpressions();
93     void basicExpressions_data();
94     void arrayExpressions();
95     void contextPropertiesTriggerReeval();
96     void objectPropertiesTriggerReeval();
97     void deferredProperties();
98     void deferredPropertiesErrors();
99     void extensionObjects();
100     void overrideExtensionProperties();
101     void attachedProperties();
102     void enums();
103     void valueTypeFunctions();
104     void constantsOverrideBindings();
105     void outerBindingOverridesInnerBinding();
106     void aliasPropertyAndBinding();
107     void nonExistentAttachedObject();
108     void scope();
109     void importScope();
110     void signalParameterTypes();
111     void objectsCompareAsEqual();
112     void dynamicCreation_data();
113     void dynamicCreation();
114     void dynamicDestruction();
115     void objectToString();
116     void selfDeletingBinding();
117     void extendedObjectPropertyLookup();
118     void scriptErrors();
119     void functionErrors();
120     void propertyAssignmentErrors();
121     void signalTriggeredBindings();
122     void listProperties();
123     void exceptionClearsOnReeval();
124     void exceptionSlotProducesWarning();
125     void exceptionBindingProducesWarning();
126     void transientErrors();
127     void shutdownErrors();
128     void compositePropertyType();
129     void jsObject();
130     void undefinedResetsProperty();
131     void listToVariant();
132     void multiEngineObject();
133     void deletedObject();
134     void attachedPropertyScope();
135     void scriptConnect();
136     void scriptDisconnect();
137     void ownership();
138     void cppOwnershipReturnValue();
139     void ownershipCustomReturnValue();
140     void qlistqobjectMethods();
141     void strictlyEquals();
142     void compiled();
143     void numberAssignment();
144     void propertySplicing();
145     void signalWithUnknownTypes();
146     void moduleApi();
147     void importScripts();
148     void scarceResources();
149     void propertyChangeSlots();
150     void elementAssign();
151     void objectPassThroughSignals();
152     void booleanConversion();
153
154     void bug1();
155     void bug2();
156     void dynamicCreationCrash();
157     void regExpBug();
158     void nullObjectBinding();
159     void deletedEngine();
160     void libraryScriptAssert();
161     void variantsAssignedUndefined();
162     void qtbug_9792();
163     void qtcreatorbug_1289();
164     void noSpuriousWarningsAtShutdown();
165     void canAssignNullToQObject();
166     void functionAssignment_fromBinding();
167     void functionAssignment_fromJS();
168     void functionAssignment_fromJS_data();
169     void functionAssignmentfromJS_invalid();
170     void eval();
171     void function();
172     void qtbug_10696();
173     void qtbug_11606();
174     void qtbug_11600();
175     void nonscriptable();
176     void deleteLater();
177     void in();
178     void sharedAttachedObject();
179     void objectName();
180     void writeRemovesBinding();
181     void aliasBindingsAssignCorrectly();
182     void aliasBindingsOverrideTarget();
183     void aliasWritesOverrideBindings();
184     void aliasToCompositeElement();
185     void realToInt();
186     void dynamicString();
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     {
1077     QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1078     QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1079     QVERIFY(object != 0);
1080     QDeclarativeGuard<QObject> createdQmlObject = 0;
1081
1082     QMetaObject::invokeMethod(object, "create");
1083     createdQmlObject = object->objectProperty();
1084     QVERIFY(createdQmlObject);
1085     QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1086
1087     QMetaObject::invokeMethod(object, "killOther");
1088     QVERIFY(createdQmlObject);
1089     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1090     QVERIFY(createdQmlObject);
1091     for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1092         if (createdQmlObject) {
1093             QTest::qWait(100);
1094             QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1095         }
1096     }
1097     QVERIFY(!createdQmlObject);
1098
1099     QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1100     QMetaObject::invokeMethod(object, "killMe");
1101     QVERIFY(object);
1102     QTest::qWait(0);
1103     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1104     QVERIFY(!object);
1105     }
1106
1107     {
1108     QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1109     QObject *o = component.create();
1110     QVERIFY(o != 0);
1111
1112     QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1113
1114     QMetaObject::invokeMethod(o, "create");
1115
1116     QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1117
1118     QMetaObject::invokeMethod(o, "destroy");
1119
1120     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1121
1122     QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1123
1124     delete o;
1125     }
1126 }
1127
1128 /*
1129    tests that id.toString() works
1130 */
1131 void tst_qdeclarativeecmascript::objectToString()
1132 {
1133     QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1134     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1135     QVERIFY(object != 0);
1136     QMetaObject::invokeMethod(object, "testToString");
1137     QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1138     QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1139
1140     delete object;
1141 }
1142
1143 /*
1144 Tests bindings that indirectly cause their own deletion work.
1145
1146 This test is best run under valgrind to ensure no invalid memory access occur.
1147 */
1148 void tst_qdeclarativeecmascript::selfDeletingBinding()
1149 {
1150     {
1151         QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1152         QObject *object = component.create();
1153         QVERIFY(object != 0);
1154         object->setProperty("triggerDelete", true);
1155         delete object;
1156     }
1157
1158     {
1159         QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1160         QObject *object = component.create();
1161         QVERIFY(object != 0);
1162         object->setProperty("triggerDelete", true);
1163         delete object;
1164     }
1165 }
1166
1167 /*
1168 Test that extended object properties can be accessed.
1169
1170 This test a regression where this used to crash.  The issue was specificially
1171 for extended objects that did not include a synthesized meta object (so non-root
1172 and no synthesiszed properties).
1173 */
1174 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1175 {
1176     QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1177     QObject *object = component.create();
1178     QVERIFY(object != 0);
1179     delete object;
1180 }
1181
1182 /*
1183 Test file/lineNumbers for binding/Script errors.
1184 */
1185 void tst_qdeclarativeecmascript::scriptErrors()
1186 {
1187     QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1188     QString url = component.url().toString();
1189
1190     QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1191     QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1192     QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1193     QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1194     QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1195     QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1196     QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1197     QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1198
1199     QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1200     QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1201     QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1202     QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1203     QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1204     MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1205     QVERIFY(object != 0);
1206
1207     QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1208     emit object->basicSignal();
1209
1210     QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1211     emit object->anotherBasicSignal();
1212
1213     QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1214     emit object->thirdBasicSignal();
1215
1216     delete object;
1217 }
1218
1219 /*
1220 Test file/lineNumbers for inline functions.
1221 */
1222 void tst_qdeclarativeecmascript::functionErrors()
1223 {
1224     QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1225     QString url = component.url().toString();
1226
1227     QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1228
1229     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1230
1231     QObject *object = component.create();
1232     QVERIFY(object != 0);
1233     delete object;
1234
1235     // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1236     QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1237     url = componentTwo.url().toString();
1238     object = componentTwo.create();
1239     QVERIFY(object != 0);
1240
1241     QString srpname = object->property("srp_name").toString();
1242     
1243     warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname + 
1244               QLatin1String(" is not a function");
1245     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1246     QMetaObject::invokeMethod(object, "retrieveScarceResource");
1247     delete object;
1248 }
1249
1250 /*
1251 Test various errors that can occur when assigning a property from script
1252 */
1253 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1254 {
1255     QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1256
1257     QString url = component.url().toString();
1258
1259     QObject *object = component.create();
1260     QVERIFY(object != 0);
1261
1262     QCOMPARE(object->property("test1").toBool(), true);
1263     QCOMPARE(object->property("test2").toBool(), true);
1264
1265     delete object;
1266 }
1267     
1268 /*
1269 Test bindings still work when the reeval is triggered from within
1270 a signal script.
1271 */
1272 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1273 {
1274     QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1275     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1276     QVERIFY(object != 0);
1277
1278     QCOMPARE(object->property("base").toReal(), 50.);
1279     QCOMPARE(object->property("test1").toReal(), 50.);
1280     QCOMPARE(object->property("test2").toReal(), 50.);
1281
1282     object->basicSignal();
1283
1284     QCOMPARE(object->property("base").toReal(), 200.);
1285     QCOMPARE(object->property("test1").toReal(), 200.);
1286     QCOMPARE(object->property("test2").toReal(), 200.);
1287
1288     object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1289
1290     QCOMPARE(object->property("base").toReal(), 400.);
1291     QCOMPARE(object->property("test1").toReal(), 400.);
1292     QCOMPARE(object->property("test2").toReal(), 400.);
1293
1294     delete object;
1295 }
1296
1297 /*
1298 Test that list properties can be iterated from ECMAScript
1299 */
1300 void tst_qdeclarativeecmascript::listProperties()
1301 {
1302     QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1303     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1304     QVERIFY(object != 0);
1305
1306     QCOMPARE(object->property("test1").toInt(), 21);
1307     QCOMPARE(object->property("test2").toInt(), 2);
1308     QCOMPARE(object->property("test3").toBool(), true);
1309     QCOMPARE(object->property("test4").toBool(), true);
1310
1311     delete object;
1312 }
1313
1314 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1315 {
1316     QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1317     QString url = component.url().toString();
1318
1319     QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1320
1321     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1322     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1323     QVERIFY(object != 0);
1324
1325     QCOMPARE(object->property("test").toBool(), false);
1326
1327     MyQmlObject object2;
1328     MyQmlObject object3;
1329     object2.setObjectProperty(&object3);
1330     object->setObjectProperty(&object2);
1331
1332     QCOMPARE(object->property("test").toBool(), true);
1333
1334     delete object;
1335 }
1336
1337 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1338 {
1339     QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1340     QString url = component.url().toString();
1341
1342     QString warning = component.url().toString() + ":6: Error: JS exception";
1343
1344     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1345     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1346     QVERIFY(object != 0);
1347     delete object;
1348 }
1349
1350 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1351 {
1352     QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1353     QString url = component.url().toString();
1354
1355     QString warning = component.url().toString() + ":5: Error: JS exception";
1356
1357     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1358     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1359     QVERIFY(object != 0);
1360     delete object;
1361 }
1362
1363 static int transientErrorsMsgCount = 0;
1364 static void transientErrorsMsgHandler(QtMsgType, const char *)
1365 {
1366     ++transientErrorsMsgCount;
1367 }
1368
1369 // Check that transient binding errors are not displayed
1370 void tst_qdeclarativeecmascript::transientErrors()
1371 {
1372     {
1373     QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1374
1375     transientErrorsMsgCount = 0;
1376     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1377
1378     QObject *object = component.create();
1379     QVERIFY(object != 0);
1380
1381     qInstallMsgHandler(old);
1382
1383     QCOMPARE(transientErrorsMsgCount, 0);
1384
1385     delete object;
1386     }
1387
1388     // One binding erroring multiple times, but then resolving
1389     {
1390     QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1391
1392     transientErrorsMsgCount = 0;
1393     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1394
1395     QObject *object = component.create();
1396     QVERIFY(object != 0);
1397
1398     qInstallMsgHandler(old);
1399
1400     QCOMPARE(transientErrorsMsgCount, 0);
1401
1402     delete object;
1403     }
1404 }
1405
1406 // Check that errors during shutdown are minimized
1407 void tst_qdeclarativeecmascript::shutdownErrors()
1408 {
1409     QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1410     QObject *object = component.create();
1411     QVERIFY(object != 0);
1412
1413     transientErrorsMsgCount = 0;
1414     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1415
1416     delete object;
1417
1418     qInstallMsgHandler(old);
1419     QCOMPARE(transientErrorsMsgCount, 0);
1420 }
1421
1422 void tst_qdeclarativeecmascript::compositePropertyType()
1423 {
1424     QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1425     QTest::ignoreMessage(QtDebugMsg, "hello world");
1426     QObject *object = qobject_cast<QObject *>(component.create());
1427     delete object;
1428 }
1429
1430 // QTBUG-5759
1431 void tst_qdeclarativeecmascript::jsObject()
1432 {
1433     QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1434     QObject *object = component.create();
1435     QVERIFY(object != 0);
1436
1437     QCOMPARE(object->property("test").toInt(), 92);
1438
1439     delete object;
1440 }
1441
1442 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1443 {
1444     {
1445     QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1446     QObject *object = component.create();
1447     QVERIFY(object != 0);
1448
1449     QCOMPARE(object->property("resettableProperty").toInt(), 92);
1450
1451     object->setProperty("setUndefined", true);
1452
1453     QCOMPARE(object->property("resettableProperty").toInt(), 13);
1454
1455     object->setProperty("setUndefined", false);
1456
1457     QCOMPARE(object->property("resettableProperty").toInt(), 92);
1458
1459     delete object;
1460     }
1461     {
1462     QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1463     QObject *object = component.create();
1464     QVERIFY(object != 0);
1465
1466     QCOMPARE(object->property("resettableProperty").toInt(), 19);
1467
1468     QMetaObject::invokeMethod(object, "doReset");
1469
1470     QCOMPARE(object->property("resettableProperty").toInt(), 13);
1471
1472     delete object;
1473     }
1474 }
1475
1476 // QTBUG-6781
1477 void tst_qdeclarativeecmascript::bug1()
1478 {
1479     QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1480     QObject *object = component.create();
1481     QVERIFY(object != 0);
1482
1483     QCOMPARE(object->property("test").toInt(), 14);
1484
1485     object->setProperty("a", 11);
1486
1487     QCOMPARE(object->property("test").toInt(), 3);
1488
1489     object->setProperty("b", true);
1490
1491     QCOMPARE(object->property("test").toInt(), 9);
1492
1493     delete object;
1494 }
1495
1496 void tst_qdeclarativeecmascript::bug2()
1497 {
1498     QDeclarativeComponent component(&engine);
1499     component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1500
1501     QObject *object = component.create();
1502     QVERIFY(object != 0);
1503
1504     delete object;
1505 }
1506
1507 // Don't crash in createObject when the component has errors.
1508 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1509 {
1510     QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1511     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1512     QVERIFY(object != 0);
1513
1514     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1515     QMetaObject::invokeMethod(object, "dontCrash");
1516     QObject *created = object->objectProperty();
1517     QVERIFY(created == 0);
1518
1519     delete object;
1520 }
1521
1522 //QTBUG-9367
1523 void tst_qdeclarativeecmascript::regExpBug()
1524 {
1525     QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1526     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1527     QVERIFY(object != 0);
1528     QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1529     delete object;
1530 }
1531
1532 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1533 {
1534     QString functionSource = QLatin1String("(function(object) { return ") + 
1535                              QLatin1String(source) + QLatin1String(" })");
1536     v8::TryCatch tc;
1537     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1538     if (tc.HasCaught())
1539         return false;
1540     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1541     if (function.IsEmpty())
1542         return false;
1543     v8::Handle<v8::Value> args[] = { o };
1544     function->Call(engine->global(), 1, args);
1545     return tc.HasCaught();
1546 }
1547
1548 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o, 
1549                                   const char *source, v8::Handle<v8::Value> result)
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 false;
1557     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1558     if (function.IsEmpty())
1559         return false;
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 false;
1566
1567     return value->StrictEquals(result);
1568 }
1569
1570 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o, 
1571                                              const char *source)
1572 {
1573     QString functionSource = QLatin1String("(function(object) { return ") + 
1574                              QLatin1String(source) + QLatin1String(" })");
1575     v8::TryCatch tc;
1576     v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1577     if (tc.HasCaught())
1578         return v8::Handle<v8::Value>();
1579     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1580     if (function.IsEmpty())
1581         return v8::Handle<v8::Value>();
1582     v8::Handle<v8::Value> args[] = { o };
1583
1584     v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1585
1586     if (tc.HasCaught())
1587         return v8::Handle<v8::Value>();
1588     return value;
1589 }
1590
1591 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1592 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1593 #define EVALUATE(source) evaluate(engine, object, source)
1594
1595 void tst_qdeclarativeecmascript::callQtInvokables()
1596 {
1597     MyInvokableObject o;
1598
1599     QDeclarativeEngine qmlengine;
1600     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1601     
1602     QV8Engine *engine = ep->v8engine();
1603
1604     v8::HandleScope handle_scope;
1605     v8::Context::Scope scope(engine->context());
1606
1607     v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1608
1609     // Non-existent methods
1610     o.reset();
1611     QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1612     QCOMPARE(o.error(), false);
1613     QCOMPARE(o.invoked(), -1);
1614     QCOMPARE(o.actuals().count(), 0);
1615
1616     o.reset();
1617     QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1618     QCOMPARE(o.error(), false);
1619     QCOMPARE(o.invoked(), -1);
1620     QCOMPARE(o.actuals().count(), 0);
1621
1622     // Insufficient arguments
1623     o.reset();
1624     QVERIFY(EVALUATE_ERROR("object.method_int()"));
1625     QCOMPARE(o.error(), false);
1626     QCOMPARE(o.invoked(), -1);
1627     QCOMPARE(o.actuals().count(), 0);
1628
1629     o.reset();
1630     QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1631     QCOMPARE(o.error(), false);
1632     QCOMPARE(o.invoked(), -1);
1633     QCOMPARE(o.actuals().count(), 0);
1634
1635     // Excessive arguments
1636     o.reset();
1637     QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1638     QCOMPARE(o.error(), false);
1639     QCOMPARE(o.invoked(), 8);
1640     QCOMPARE(o.actuals().count(), 1);
1641     QCOMPARE(o.actuals().at(0), QVariant(10));
1642
1643     o.reset();
1644     QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1645     QCOMPARE(o.error(), false);
1646     QCOMPARE(o.invoked(), 9);
1647     QCOMPARE(o.actuals().count(), 2);
1648     QCOMPARE(o.actuals().at(0), QVariant(10));
1649     QCOMPARE(o.actuals().at(1), QVariant(11));
1650
1651     // Test return types
1652     o.reset();
1653     QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1654     QCOMPARE(o.error(), false);
1655     QCOMPARE(o.invoked(), 0);
1656     QCOMPARE(o.actuals().count(), 0);
1657
1658     o.reset();
1659     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1660     QCOMPARE(o.error(), false);
1661     QCOMPARE(o.invoked(), 1);
1662     QCOMPARE(o.actuals().count(), 0);
1663
1664     o.reset();
1665     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1666     QCOMPARE(o.error(), false);
1667     QCOMPARE(o.invoked(), 2);
1668     QCOMPARE(o.actuals().count(), 0);
1669
1670     o.reset();
1671     {
1672     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1673     QVERIFY(!ret.IsEmpty());
1674     QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1675     QCOMPARE(o.error(), false);
1676     QCOMPARE(o.invoked(), 3);
1677     QCOMPARE(o.actuals().count(), 0);
1678     }
1679
1680     o.reset();
1681     {
1682     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1683     QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1684     QCOMPARE(o.error(), false);
1685     QCOMPARE(o.invoked(), 4);
1686     QCOMPARE(o.actuals().count(), 0);
1687     }
1688
1689     o.reset();
1690     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1691     QCOMPARE(o.error(), false);
1692     QCOMPARE(o.invoked(), 5);
1693     QCOMPARE(o.actuals().count(), 0);
1694
1695     o.reset();
1696     {
1697     v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1698     QVERIFY(ret->IsString());
1699     QCOMPARE(engine->toString(ret), QString("Hello world"));
1700     QCOMPARE(o.error(), false);
1701     QCOMPARE(o.invoked(), 6);
1702     QCOMPARE(o.actuals().count(), 0);
1703     }
1704
1705     o.reset();
1706     QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1707     QCOMPARE(o.error(), false);
1708     QCOMPARE(o.invoked(), 7);
1709     QCOMPARE(o.actuals().count(), 0);
1710
1711     // Test arg types
1712     o.reset();
1713     QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1714     QCOMPARE(o.error(), false);
1715     QCOMPARE(o.invoked(), 8);
1716     QCOMPARE(o.actuals().count(), 1);
1717     QCOMPARE(o.actuals().at(0), QVariant(94));
1718
1719     o.reset();
1720     QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1721     QCOMPARE(o.error(), false);
1722     QCOMPARE(o.invoked(), 8);
1723     QCOMPARE(o.actuals().count(), 1);
1724     QCOMPARE(o.actuals().at(0), QVariant(94));
1725
1726     o.reset();
1727     QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1728     QCOMPARE(o.error(), false);
1729     QCOMPARE(o.invoked(), 8);
1730     QCOMPARE(o.actuals().count(), 1);
1731     QCOMPARE(o.actuals().at(0), QVariant(0));
1732
1733     o.reset();
1734     QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1735     QCOMPARE(o.error(), false);
1736     QCOMPARE(o.invoked(), 8);
1737     QCOMPARE(o.actuals().count(), 1);
1738     QCOMPARE(o.actuals().at(0), QVariant(0));
1739
1740     o.reset();
1741     QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1742     QCOMPARE(o.error(), false);
1743     QCOMPARE(o.invoked(), 8);
1744     QCOMPARE(o.actuals().count(), 1);
1745     QCOMPARE(o.actuals().at(0), QVariant(0));
1746
1747     o.reset();
1748     QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1749     QCOMPARE(o.error(), false);
1750     QCOMPARE(o.invoked(), 8);
1751     QCOMPARE(o.actuals().count(), 1);
1752     QCOMPARE(o.actuals().at(0), QVariant(0));
1753
1754     o.reset();
1755     QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1756     QCOMPARE(o.error(), false);
1757     QCOMPARE(o.invoked(), 9);
1758     QCOMPARE(o.actuals().count(), 2);
1759     QCOMPARE(o.actuals().at(0), QVariant(122));
1760     QCOMPARE(o.actuals().at(1), QVariant(9));
1761
1762     o.reset();
1763     QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1764     QCOMPARE(o.error(), false);
1765     QCOMPARE(o.invoked(), 10);
1766     QCOMPARE(o.actuals().count(), 1);
1767     QCOMPARE(o.actuals().at(0), QVariant(94.3));
1768
1769     o.reset();
1770     QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1771     QCOMPARE(o.error(), false);
1772     QCOMPARE(o.invoked(), 10);
1773     QCOMPARE(o.actuals().count(), 1);
1774     QCOMPARE(o.actuals().at(0), QVariant(94.3));
1775
1776     o.reset();
1777     QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1778     QCOMPARE(o.error(), false);
1779     QCOMPARE(o.invoked(), 10);
1780     QCOMPARE(o.actuals().count(), 1);
1781     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1782
1783     o.reset();
1784     QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1785     QCOMPARE(o.error(), false);
1786     QCOMPARE(o.invoked(), 10);
1787     QCOMPARE(o.actuals().count(), 1);
1788     QCOMPARE(o.actuals().at(0), QVariant(0));
1789
1790     o.reset();
1791     QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1792     QCOMPARE(o.error(), false);
1793     QCOMPARE(o.invoked(), 10);
1794     QCOMPARE(o.actuals().count(), 1);
1795     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1796
1797     o.reset();
1798     QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1799     QCOMPARE(o.error(), false);
1800     QCOMPARE(o.invoked(), 10);
1801     QCOMPARE(o.actuals().count(), 1);
1802     QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1803
1804     o.reset();
1805     QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1806     QCOMPARE(o.error(), false);
1807     QCOMPARE(o.invoked(), 11);
1808     QCOMPARE(o.actuals().count(), 1);
1809     QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1810
1811     o.reset();
1812     QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1813     QCOMPARE(o.error(), false);
1814     QCOMPARE(o.invoked(), 11);
1815     QCOMPARE(o.actuals().count(), 1);
1816     QCOMPARE(o.actuals().at(0), QVariant("19"));
1817
1818     o.reset();
1819     {
1820     QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1821     QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1822     QCOMPARE(o.error(), false);
1823     QCOMPARE(o.invoked(), 11);
1824     QCOMPARE(o.actuals().count(), 1);
1825     QCOMPARE(o.actuals().at(0), QVariant(expected));
1826     }
1827
1828     o.reset();
1829     QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1830     QCOMPARE(o.error(), false);
1831     QCOMPARE(o.invoked(), 11);
1832     QCOMPARE(o.actuals().count(), 1);
1833     QCOMPARE(o.actuals().at(0), QVariant(QString()));
1834
1835     o.reset();
1836     QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1837     QCOMPARE(o.error(), false);
1838     QCOMPARE(o.invoked(), 11);
1839     QCOMPARE(o.actuals().count(), 1);
1840     QCOMPARE(o.actuals().at(0), QVariant(QString()));
1841
1842     o.reset();
1843     QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1844     QCOMPARE(o.error(), false);
1845     QCOMPARE(o.invoked(), 12);
1846     QCOMPARE(o.actuals().count(), 1);
1847     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1848
1849     o.reset();
1850     QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1851     QCOMPARE(o.error(), false);
1852     QCOMPARE(o.invoked(), 12);
1853     QCOMPARE(o.actuals().count(), 1);
1854     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1855
1856     o.reset();
1857     QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1858     QCOMPARE(o.error(), false);
1859     QCOMPARE(o.invoked(), 12);
1860     QCOMPARE(o.actuals().count(), 1);
1861     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1862
1863     o.reset();
1864     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
1865     QCOMPARE(o.error(), false);
1866     QCOMPARE(o.invoked(), 12);
1867     QCOMPARE(o.actuals().count(), 1);
1868     QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1869
1870     o.reset();
1871     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
1872     QCOMPARE(o.error(), false);
1873     QCOMPARE(o.invoked(), 12);
1874     QCOMPARE(o.actuals().count(), 1);
1875     QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
1876
1877     o.reset();
1878     QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
1879     QCOMPARE(o.error(), false);
1880     QCOMPARE(o.invoked(), 12);
1881     QCOMPARE(o.actuals().count(), 1);
1882     QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
1883
1884     o.reset();
1885     QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
1886     QCOMPARE(o.error(), false);
1887     QCOMPARE(o.invoked(), 13);
1888     QCOMPARE(o.actuals().count(), 1);
1889     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1890
1891     o.reset();
1892     QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
1893     QCOMPARE(o.error(), false);
1894     QCOMPARE(o.invoked(), 13);
1895     QCOMPARE(o.actuals().count(), 1);
1896     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1897
1898     o.reset();
1899     QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
1900     QCOMPARE(o.error(), false);
1901     QCOMPARE(o.invoked(), 13);
1902     QCOMPARE(o.actuals().count(), 1);
1903     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1904
1905     o.reset();
1906     QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
1907     QCOMPARE(o.error(), false);
1908     QCOMPARE(o.invoked(), 13);
1909     QCOMPARE(o.actuals().count(), 1);
1910     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1911
1912     o.reset();
1913     QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
1914     QCOMPARE(o.error(), false);
1915     QCOMPARE(o.invoked(), 13);
1916     QCOMPARE(o.actuals().count(), 1);
1917     QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
1918
1919     o.reset();
1920     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
1921     QCOMPARE(o.error(), false);
1922     QCOMPARE(o.invoked(), 14);
1923     QCOMPARE(o.actuals().count(), 1);
1924     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
1925
1926     o.reset();
1927     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
1928     QCOMPARE(o.error(), false);
1929     QCOMPARE(o.invoked(), 14);
1930     QCOMPARE(o.actuals().count(), 1);
1931     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
1932
1933     o.reset();
1934     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
1935     QCOMPARE(o.error(), false);
1936     QCOMPARE(o.invoked(), 14);
1937     QCOMPARE(o.actuals().count(), 1);
1938     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
1939
1940     o.reset();
1941     QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
1942     QCOMPARE(o.error(), false);
1943     QCOMPARE(o.invoked(), 14);
1944     QCOMPARE(o.actuals().count(), 1);
1945     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
1946
1947     o.reset();
1948     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
1949     QCOMPARE(o.error(), false);
1950     QCOMPARE(o.invoked(), 15);
1951     QCOMPARE(o.actuals().count(), 2);
1952     QCOMPARE(o.actuals().at(0), QVariant(4));
1953     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
1954
1955     o.reset();
1956     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
1957     QCOMPARE(o.error(), false);
1958     QCOMPARE(o.invoked(), 15);
1959     QCOMPARE(o.actuals().count(), 2);
1960     QCOMPARE(o.actuals().at(0), QVariant(8));
1961     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
1962
1963     o.reset();
1964     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
1965     QCOMPARE(o.error(), false);
1966     QCOMPARE(o.invoked(), 15);
1967     QCOMPARE(o.actuals().count(), 2);
1968     QCOMPARE(o.actuals().at(0), QVariant(3));
1969     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
1970
1971     o.reset();
1972     QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
1973     QCOMPARE(o.error(), false);
1974     QCOMPARE(o.invoked(), 15);
1975     QCOMPARE(o.actuals().count(), 2);
1976     QCOMPARE(o.actuals().at(0), QVariant(44));
1977     QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
1978
1979     o.reset();
1980     QVERIFY(EVALUATE_ERROR("object.method_overload()"));
1981     QCOMPARE(o.error(), false);
1982     QCOMPARE(o.invoked(), -1);
1983     QCOMPARE(o.actuals().count(), 0);
1984
1985     o.reset();
1986     QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
1987     QCOMPARE(o.error(), false);
1988     QCOMPARE(o.invoked(), 16);
1989     QCOMPARE(o.actuals().count(), 1);
1990     QCOMPARE(o.actuals().at(0), QVariant(10));
1991
1992     o.reset();
1993     QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
1994     QCOMPARE(o.error(), false);
1995     QCOMPARE(o.invoked(), 17);
1996     QCOMPARE(o.actuals().count(), 2);
1997     QCOMPARE(o.actuals().at(0), QVariant(10));
1998     QCOMPARE(o.actuals().at(1), QVariant(11));
1999
2000     o.reset();
2001     QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2002     QCOMPARE(o.error(), false);
2003     QCOMPARE(o.invoked(), 18);
2004     QCOMPARE(o.actuals().count(), 1);
2005     QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2006
2007     o.reset();
2008     QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2009     QCOMPARE(o.error(), false);
2010     QCOMPARE(o.invoked(), 19);
2011     QCOMPARE(o.actuals().count(), 1);
2012     QCOMPARE(o.actuals().at(0), QVariant(9));
2013
2014     o.reset();
2015     QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2016     QCOMPARE(o.error(), false);
2017     QCOMPARE(o.invoked(), 20);
2018     QCOMPARE(o.actuals().count(), 2);
2019     QCOMPARE(o.actuals().at(0), QVariant(10));
2020     QCOMPARE(o.actuals().at(1), QVariant(19));
2021
2022     o.reset();
2023     QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2024     QCOMPARE(o.error(), false);
2025     QCOMPARE(o.invoked(), 20);
2026     QCOMPARE(o.actuals().count(), 2);
2027     QCOMPARE(o.actuals().at(0), QVariant(10));
2028     QCOMPARE(o.actuals().at(1), QVariant(13));
2029
2030     o.reset();
2031     QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2032     QCOMPARE(o.error(), false);
2033     QCOMPARE(o.invoked(), -3);
2034     QCOMPARE(o.actuals().count(), 1);
2035     QCOMPARE(o.actuals().at(0), QVariant(9));
2036
2037     o.reset();
2038     QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2039     QCOMPARE(o.error(), false);
2040     QCOMPARE(o.invoked(), 21);
2041     QCOMPARE(o.actuals().count(), 2);
2042     QCOMPARE(o.actuals().at(0), QVariant(9));
2043     QCOMPARE(o.actuals().at(1), QVariant());
2044
2045     o.reset();
2046     QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2047     QCOMPARE(o.error(), false);
2048     QCOMPARE(o.invoked(), 21);
2049     QCOMPARE(o.actuals().count(), 2);
2050     QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2051     QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2052 }
2053
2054 // QTBUG-13047 (check that you can pass registered object types as args)
2055 void tst_qdeclarativeecmascript::invokableObjectArg()
2056 {
2057     QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2058
2059     QObject *o = component.create();
2060     QVERIFY(o);
2061     MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2062     QVERIFY(qmlobject);
2063     QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2064
2065     delete o;
2066 }
2067
2068 // QTBUG-13047 (check that you can return registered object types from methods)
2069 void tst_qdeclarativeecmascript::invokableObjectRet()
2070 {
2071     QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2072
2073     QObject *o = component.create();
2074     QVERIFY(o);
2075     QCOMPARE(o->property("test").toBool(), true);
2076     delete o;
2077 }
2078
2079 // QTBUG-5675
2080 void tst_qdeclarativeecmascript::listToVariant()
2081 {
2082     QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2083
2084     MyQmlContainer container;
2085
2086     QDeclarativeContext context(engine.rootContext());
2087     context.setContextObject(&container);
2088
2089     QObject *object = component.create(&context);
2090     QVERIFY(object != 0);
2091
2092     QVariant v = object->property("test");
2093     QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2094     QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2095
2096     delete object;
2097 }
2098
2099 // QTBUG-7957
2100 void tst_qdeclarativeecmascript::multiEngineObject()
2101 {
2102     MyQmlObject obj;
2103     obj.setStringProperty("Howdy planet");
2104
2105     QDeclarativeEngine e1;
2106     e1.rootContext()->setContextProperty("thing", &obj);
2107     QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2108
2109     QDeclarativeEngine e2;
2110     e2.rootContext()->setContextProperty("thing", &obj);
2111     QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2112
2113     QObject *o1 = c1.create();
2114     QObject *o2 = c2.create();
2115
2116     QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2117     QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2118
2119     delete o2;
2120     delete o1;
2121 }
2122
2123 // Test that references to QObjects are cleanup when the object is destroyed
2124 void tst_qdeclarativeecmascript::deletedObject()
2125 {
2126     QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2127
2128     QObject *object = component.create();
2129
2130     QCOMPARE(object->property("test1").toBool(), true);
2131     QCOMPARE(object->property("test2").toBool(), true);
2132     QCOMPARE(object->property("test3").toBool(), true);
2133     QCOMPARE(object->property("test4").toBool(), true);
2134
2135     delete object;
2136 }
2137
2138 void tst_qdeclarativeecmascript::attachedPropertyScope()
2139 {
2140     QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2141
2142     QObject *object = component.create();
2143     QVERIFY(object != 0);
2144
2145     MyQmlAttachedObject *attached = 
2146         qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2147     QVERIFY(attached != 0);
2148
2149     QCOMPARE(object->property("value2").toInt(), 0);
2150
2151     attached->emitMySignal();
2152
2153     QCOMPARE(object->property("value2").toInt(), 9);
2154
2155     delete object;
2156 }
2157
2158 void tst_qdeclarativeecmascript::scriptConnect()
2159 {
2160     {
2161         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2162
2163         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2164         QVERIFY(object != 0);
2165
2166         QCOMPARE(object->property("test").toBool(), false);
2167         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2168         QCOMPARE(object->property("test").toBool(), true);
2169
2170         delete object;
2171     }
2172
2173     {
2174         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2175
2176         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2177         QVERIFY(object != 0);
2178
2179         QCOMPARE(object->property("test").toBool(), false);
2180         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2181         QCOMPARE(object->property("test").toBool(), true);
2182
2183         delete object;
2184     }
2185
2186     {
2187         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2188
2189         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2190         QVERIFY(object != 0);
2191
2192         QCOMPARE(object->property("test").toBool(), false);
2193         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2194         QCOMPARE(object->property("test").toBool(), true);
2195
2196         delete object;
2197     }
2198
2199     {
2200         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2201
2202         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2203         QVERIFY(object != 0);
2204
2205         QCOMPARE(object->methodCalled(), false);
2206         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2207         QCOMPARE(object->methodCalled(), true);
2208
2209         delete object;
2210     }
2211
2212     {
2213         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2214
2215         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2216         QVERIFY(object != 0);
2217
2218         QCOMPARE(object->methodCalled(), false);
2219         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2220         QCOMPARE(object->methodCalled(), true);
2221
2222         delete object;
2223     }
2224
2225     {
2226         QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.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(), 2);
2234
2235         delete object;
2236     }
2237 }
2238
2239 void tst_qdeclarativeecmascript::scriptDisconnect()
2240 {
2241     {
2242         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2243
2244         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2245         QVERIFY(object != 0);
2246
2247         QCOMPARE(object->property("test").toInt(), 0);
2248         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2249         QCOMPARE(object->property("test").toInt(), 1);
2250         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2251         QCOMPARE(object->property("test").toInt(), 2);
2252         emit object->basicSignal();
2253         QCOMPARE(object->property("test").toInt(), 2);
2254         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2255         QCOMPARE(object->property("test").toInt(), 2);
2256
2257         delete object;
2258     }
2259
2260     {
2261         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2262
2263         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2264         QVERIFY(object != 0);
2265
2266         QCOMPARE(object->property("test").toInt(), 0);
2267         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2268         QCOMPARE(object->property("test").toInt(), 1);
2269         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2270         QCOMPARE(object->property("test").toInt(), 2);
2271         emit object->basicSignal();
2272         QCOMPARE(object->property("test").toInt(), 2);
2273         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2274         QCOMPARE(object->property("test").toInt(), 2);
2275
2276         delete object;
2277     }
2278
2279     {
2280         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2281
2282         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2283         QVERIFY(object != 0);
2284
2285         QCOMPARE(object->property("test").toInt(), 0);
2286         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2287         QCOMPARE(object->property("test").toInt(), 1);
2288         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2289         QCOMPARE(object->property("test").toInt(), 2);
2290         emit object->basicSignal();
2291         QCOMPARE(object->property("test").toInt(), 2);
2292         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2293         QCOMPARE(object->property("test").toInt(), 3);
2294
2295         delete object;
2296     }
2297     {
2298         QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2299
2300         MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2301         QVERIFY(object != 0);
2302
2303         QCOMPARE(object->property("test").toInt(), 0);
2304         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2305         QCOMPARE(object->property("test").toInt(), 1);
2306         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2307         QCOMPARE(object->property("test").toInt(), 2);
2308         emit object->basicSignal();
2309         QCOMPARE(object->property("test").toInt(), 2);
2310         emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2311         QCOMPARE(object->property("test").toInt(), 3);
2312
2313         delete object;
2314     }
2315 }
2316
2317 class OwnershipObject : public QObject
2318 {
2319     Q_OBJECT
2320 public:
2321     OwnershipObject() { object = new QObject; }
2322
2323     QPointer<QObject> object;
2324
2325 public slots:
2326     QObject *getObject() { return object; }
2327 };
2328
2329 void tst_qdeclarativeecmascript::ownership()
2330 {
2331     OwnershipObject own;
2332     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2333     context->setContextObject(&own);
2334
2335     {
2336         QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2337
2338         QVERIFY(own.object != 0);
2339
2340         QObject *object = component.create(context);
2341
2342         engine.collectGarbage();
2343
2344         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2345
2346         QVERIFY(own.object == 0);
2347
2348         delete object;
2349     }
2350
2351     own.object = new QObject(&own);
2352
2353     {
2354         QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2355
2356         QVERIFY(own.object != 0);
2357
2358         QObject *object = component.create(context);
2359         
2360         engine.collectGarbage();
2361
2362         QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2363
2364         QVERIFY(own.object != 0);
2365
2366         delete object;
2367     }
2368
2369     delete context;
2370 }
2371
2372 class CppOwnershipReturnValue : public QObject
2373 {
2374     Q_OBJECT
2375 public:
2376     CppOwnershipReturnValue() : value(0) {}
2377     ~CppOwnershipReturnValue() { delete value; }
2378
2379     Q_INVOKABLE QObject *create() {
2380         value = new QObject;
2381         QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2382         return value;
2383     }
2384
2385     Q_INVOKABLE MyQmlObject *createQmlObject() {
2386         MyQmlObject *rv = new MyQmlObject;
2387         value = rv;
2388         return rv;
2389     }
2390
2391     QPointer<QObject> value;
2392 };
2393
2394 // QTBUG-15695.  
2395 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2396 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2397 {
2398     CppOwnershipReturnValue source;
2399
2400     {
2401     QDeclarativeEngine engine;
2402     engine.rootContext()->setContextProperty("source", &source);
2403
2404     QVERIFY(source.value == 0);
2405
2406     QDeclarativeComponent component(&engine);
2407     component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2408
2409     QObject *object = component.create();
2410
2411     QVERIFY(object != 0);
2412     QVERIFY(source.value != 0);
2413
2414     delete object;
2415     }
2416
2417     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2418
2419     QVERIFY(source.value != 0);
2420 }
2421
2422 // QTBUG-15697
2423 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2424 {
2425     CppOwnershipReturnValue source;
2426
2427     {
2428     QDeclarativeEngine engine;
2429     engine.rootContext()->setContextProperty("source", &source);
2430
2431     QVERIFY(source.value == 0);
2432
2433     QDeclarativeComponent component(&engine);
2434     component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2435
2436     QObject *object = component.create();
2437
2438     QVERIFY(object != 0);
2439     QVERIFY(source.value != 0);
2440
2441     delete object;
2442     }
2443
2444     engine.collectGarbage();
2445     QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2446
2447     QVERIFY(source.value == 0);
2448 }
2449
2450 class QListQObjectMethodsObject : public QObject
2451 {
2452     Q_OBJECT
2453 public:
2454     QListQObjectMethodsObject() {
2455         m_objects.append(new MyQmlObject());
2456         m_objects.append(new MyQmlObject());
2457     }
2458
2459     ~QListQObjectMethodsObject() {
2460         qDeleteAll(m_objects);
2461     }
2462
2463 public slots:
2464     QList<QObject *> getObjects() { return m_objects; }
2465
2466 private:
2467     QList<QObject *> m_objects;
2468 };
2469
2470 // Tests that returning a QList<QObject*> from a method works
2471 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2472 {
2473     QListQObjectMethodsObject obj;
2474     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2475     context->setContextObject(&obj);
2476
2477     QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2478
2479     QObject *object = component.create(context);
2480
2481     QCOMPARE(object->property("test").toInt(), 2);
2482     QCOMPARE(object->property("test2").toBool(), true);
2483
2484     delete object;
2485     delete context;
2486 }
2487
2488 // QTBUG-9205
2489 void tst_qdeclarativeecmascript::strictlyEquals()
2490 {
2491     QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2492
2493     QObject *object = component.create();
2494     QVERIFY(object != 0);
2495
2496     QCOMPARE(object->property("test1").toBool(), true);
2497     QCOMPARE(object->property("test2").toBool(), true);
2498     QCOMPARE(object->property("test3").toBool(), true);
2499     QCOMPARE(object->property("test4").toBool(), true);
2500     QCOMPARE(object->property("test5").toBool(), true);
2501     QCOMPARE(object->property("test6").toBool(), true);
2502     QCOMPARE(object->property("test7").toBool(), true);
2503     QCOMPARE(object->property("test8").toBool(), true);
2504
2505     delete object;
2506 }
2507
2508 void tst_qdeclarativeecmascript::compiled()
2509 {
2510     QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2511
2512     QObject *object = component.create();
2513     QVERIFY(object != 0);
2514
2515     QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2516     QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2517     QCOMPARE(object->property("test3").toBool(), true);
2518     QCOMPARE(object->property("test4").toBool(), false);
2519     QCOMPARE(object->property("test5").toBool(), false);
2520     QCOMPARE(object->property("test6").toBool(), true);
2521
2522     QCOMPARE(object->property("test7").toInt(), 185);
2523     QCOMPARE(object->property("test8").toInt(), 167);
2524     QCOMPARE(object->property("test9").toBool(), true);
2525     QCOMPARE(object->property("test10").toBool(), false);
2526     QCOMPARE(object->property("test11").toBool(), false);
2527     QCOMPARE(object->property("test12").toBool(), true);
2528
2529     QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2530     QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2531     QCOMPARE(object->property("test15").toBool(), false);
2532     QCOMPARE(object->property("test16").toBool(), true);
2533
2534     QCOMPARE(object->property("test17").toInt(), 5);
2535     QCOMPARE(object->property("test18").toReal(), qreal(176));
2536     QCOMPARE(object->property("test19").toInt(), 7);
2537     QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2538     QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2539     QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2540     QCOMPARE(object->property("test23").toBool(), true);
2541     QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2542     QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2543
2544     delete object;
2545 }
2546
2547 // Test that numbers assigned in bindings as strings work consistently
2548 void tst_qdeclarativeecmascript::numberAssignment()
2549 {
2550     QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2551
2552     QObject *object = component.create();
2553     QVERIFY(object != 0);
2554
2555     QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2556     QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2557     QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2558     QCOMPARE(object->property("test3"), QVariant((qreal)6));
2559     QCOMPARE(object->property("test4"), QVariant((qreal)6));
2560
2561     QCOMPARE(object->property("test5"), QVariant((int)7));
2562     QCOMPARE(object->property("test6"), QVariant((int)7));
2563     QCOMPARE(object->property("test7"), QVariant((int)6));
2564     QCOMPARE(object->property("test8"), QVariant((int)6));
2565
2566     QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2567     QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2568     QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2569     QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2570
2571     delete object;
2572 }
2573
2574 void tst_qdeclarativeecmascript::propertySplicing()
2575 {
2576     QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2577
2578     QObject *object = component.create();
2579     QVERIFY(object != 0);
2580
2581     QCOMPARE(object->property("test").toBool(), true);
2582
2583     delete object;
2584 }
2585
2586 // QTBUG-16683
2587 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2588 {
2589     QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2590
2591     MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2592     QVERIFY(object != 0);
2593
2594     MyQmlObject::MyType type;
2595     type.value = 0x8971123;
2596     emit object->signalWithUnknownType(type);
2597
2598     MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2599
2600     QCOMPARE(result.value, type.value);
2601
2602
2603     delete object;
2604 }
2605
2606 void tst_qdeclarativeecmascript::moduleApi()
2607 {
2608     QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
2609     QObject *object = component.create();
2610     QVERIFY(object != 0);
2611     QCOMPARE(object->property("existingUriTest").toInt(), 20);
2612
2613     QEXPECT_FAIL("", "QTBUG-17318", Continue);
2614     QCOMPARE(object->property("scriptTest").toInt(), 13);
2615     QCOMPARE(object->property("qobjectTest").toInt(), 20);
2616     QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
2617     QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
2618     QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
2619     QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
2620     delete object;
2621
2622     // test that caching of module apis works correctly.
2623     QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
2624     object = componentTwo.create();
2625     QVERIFY(object != 0);
2626     QCOMPARE(object->property("existingUriTest").toInt(), 20);
2627     QEXPECT_FAIL("", "QTBUG-17318", Continue);
2628     QCOMPARE(object->property("scriptTest").toInt(), 13);            // shouldn't have incremented.
2629     QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);   // shouldn't have incremented.
2630     delete object;
2631
2632     // test that writing to a property of module apis works correctly.
2633     QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
2634     QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
2635     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2636     object = componentThree.create();
2637     QVERIFY(object != 0);
2638     QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2639     QCOMPARE(object->property("writableProperty").toInt(), 50);
2640     QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
2641     QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
2642     QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2643     QCOMPARE(object->property("writableProperty").toInt(), 30);
2644     delete object;
2645
2646     QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
2647     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2648     object = failOne.create();
2649     QVERIFY(object == 0); // should have failed: invalid major version
2650
2651     QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
2652     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2653     object = failTwo.create();
2654     QVERIFY(object == 0); // should have failed: invalid minor version
2655 }
2656
2657 void tst_qdeclarativeecmascript::importScripts()
2658 {
2659     QObject *object = 0;
2660
2661     // first, ensure that the required behaviour works.
2662     QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2663     object = component.create();
2664     QVERIFY(object != 0);
2665     QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2666     QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2667     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2668     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2669     delete object;
2670
2671     QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2672     object = componentTwo.create();
2673     QVERIFY(object != 0);
2674     QCOMPARE(object->property("componentError"), QVariant(5));
2675     delete object;
2676
2677     // then, ensure that unintended behaviour does not work.
2678     QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2679     QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2680     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2681     object = failOneComponent.create();
2682     QVERIFY(object != 0);
2683     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2684     delete object;
2685     QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2686     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2687     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2688     object = failTwoComponent.create();
2689     QVERIFY(object != 0);
2690     QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2691     delete object;
2692     QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2693     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2694     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2695     object = failThreeComponent.create();
2696     QVERIFY(object != 0);
2697     QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2698     delete object;
2699     QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2700     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2701     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2702     object = failFourComponent.create();
2703     QVERIFY(object != 0);
2704     QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2705     delete object;
2706     QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2707     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2708     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2709     expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2710     QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2711     object = failFiveComponent.create();
2712     QVERIFY(object != 0);
2713     QCOMPARE(object->property("componentError"), QVariant(0));
2714     delete object;
2715
2716     // also, test that importing scripts with .pragma library works as required
2717     QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2718     object = pragmaLibraryComponent.create();
2719     QVERIFY(object != 0);
2720     QCOMPARE(object->property("testValue"), QVariant(31));
2721     delete object;
2722
2723     // and that .pragma library scripts don't inherit imports from any .qml file
2724     QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2725     object = pragmaLibraryComponentTwo.create();
2726     QVERIFY(object != 0);
2727     QCOMPARE(object->property("testValue"), QVariant(0));
2728     delete object;
2729 }
2730
2731 void tst_qdeclarativeecmascript::scarceResources()
2732 {
2733     QPixmap origPixmap(100, 100);
2734     origPixmap.fill(Qt::blue);
2735
2736     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2737     ScarceResourceObject *eo = 0;
2738     QObject *object = 0;
2739
2740     // in the following three cases, the instance created from the component
2741     // has a property which is a copy of the scarce resource; hence, the
2742     // resource should NOT be detached prior to deletion of the object instance,
2743     // unless the resource is destroyed explicitly.
2744     QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2745     object = component.create();
2746     QVERIFY(object != 0);
2747     QVERIFY(object->property("scarceResourceCopy").isValid());
2748     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2749     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2750     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2751     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2752     delete object;
2753
2754     QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2755     object = componentTwo.create();
2756     QVERIFY(object != 0);
2757     QVERIFY(object->property("scarceResourceCopy").isValid());
2758     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2759     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2760     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2761     QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2762     delete object;
2763
2764     QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
2765     object = componentThree.create();
2766     QVERIFY(object != 0);
2767     QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
2768     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2769     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2770     QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
2771     delete object;
2772
2773     // in the following three cases, no other copy should exist in memory,
2774     // and so it should be detached (unless explicitly preserved).
2775     QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
2776     object = componentFour.create();
2777     QVERIFY(object != 0);
2778     QVERIFY(object->property("scarceResourceTest").isValid());
2779     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2780     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2781     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2782     QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
2783     delete object;
2784
2785     QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
2786     object = componentFive.create();
2787     QVERIFY(object != 0);
2788     QVERIFY(object->property("scarceResourceTest").isValid());
2789     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2790     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2791     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2792     QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
2793     delete object;
2794
2795     QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
2796     object = componentSix.create();
2797     QVERIFY(object != 0);
2798     QVERIFY(object->property("scarceResourceTest").isValid());
2799     QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2800     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2801     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2802     QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
2803     delete object;
2804
2805     // test that scarce resources are handled correctly for imports
2806     QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
2807     object = componentSeven.create();
2808     QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
2809     QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
2810     delete object;
2811
2812     QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
2813     object = componentEight.create();
2814     QVERIFY(object != 0);
2815     QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
2816     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2817     delete object;
2818
2819     QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
2820     object = componentNine.create();
2821     QVERIFY(object != 0);
2822     QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
2823     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2824     QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
2825     QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
2826     QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
2827     QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
2828     delete object;
2829
2830     // test that scarce resources are handled properly in signal invocation
2831     QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
2832     object = componentTen.create();
2833     QVERIFY(object != 0);
2834     QObject *srsc = object->findChild<QObject*>("srsc");
2835     QVERIFY(srsc);
2836     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
2837     QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
2838     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2839     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2840     QMetaObject::invokeMethod(srsc, "testSignal");
2841     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
2842     QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
2843     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2844     QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
2845     QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
2846     QVERIFY(srsc->property("scarceResourceCopy").isValid());
2847     QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2848     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2849     QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
2850     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2851     delete object;
2852
2853     // test that scarce resources are handled properly from js functions in qml files
2854     QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
2855     object = componentEleven.create();
2856     QVERIFY(object != 0);
2857     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2858     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2859     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2860     QMetaObject::invokeMethod(object, "retrieveScarceResource");
2861     QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
2862     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2863     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2864     QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
2865     QMetaObject::invokeMethod(object, "releaseScarceResource");
2866     QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
2867     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2868     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2869     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2870     delete object;
2871
2872     // test that if an exception occurs while invoking js function from cpp, that the resources are released.
2873     QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
2874     object = componentTwelve.create();
2875     QVERIFY(object != 0);
2876     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2877     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2878     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2879     QString srp_name = object->property("srp_name").toString();
2880     QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
2881     QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
2882     QMetaObject::invokeMethod(object, "retrieveScarceResource");
2883     QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
2884     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2885     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2886     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2887     delete object;
2888 }
2889
2890 void tst_qdeclarativeecmascript::propertyChangeSlots()
2891 {
2892     // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
2893     QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
2894     QObject *object = component.create();
2895     QVERIFY(object != 0);
2896     delete object;
2897
2898     // ensure that invalid property names fail properly.
2899     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2900     QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
2901     QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
2902     QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
2903     object = e1.create();
2904     QVERIFY(object == 0);
2905     delete object;
2906
2907     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2908     QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
2909     expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
2910     QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
2911     object = e2.create();
2912     QVERIFY(object == 0);
2913     delete object;
2914
2915     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2916     QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
2917     expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
2918     QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
2919     object = e3.create();
2920     QVERIFY(object == 0);
2921     delete object;
2922
2923     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2924     QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
2925     expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
2926     QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
2927     object = e4.create();
2928     QVERIFY(object == 0);
2929     delete object;
2930 }
2931
2932 // Ensure that QObject type conversion works on binding assignment
2933 void tst_qdeclarativeecmascript::elementAssign()
2934 {
2935     QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
2936
2937     QObject *object = component.create();
2938     QVERIFY(object != 0);
2939
2940     QCOMPARE(object->property("test").toBool(), true);
2941
2942     delete object;
2943 }
2944
2945 // QTBUG-12457
2946 void tst_qdeclarativeecmascript::objectPassThroughSignals()
2947 {
2948     QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
2949
2950     QObject *object = component.create();
2951     QVERIFY(object != 0);
2952
2953     QCOMPARE(object->property("test").toBool(), true);
2954
2955     delete object;
2956 }
2957
2958 // QTBUG-20242
2959 void tst_qdeclarativeecmascript::booleanConversion()
2960 {
2961     QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
2962
2963     QObject *object = component.create();
2964     QVERIFY(object != 0);
2965
2966     QCOMPARE(object->property("test_true1").toBool(), true);
2967     QCOMPARE(object->property("test_true2").toBool(), true);
2968     QCOMPARE(object->property("test_true3").toBool(), true);
2969     QCOMPARE(object->property("test_true4").toBool(), true);
2970     QCOMPARE(object->property("test_true5").toBool(), true);
2971
2972     QCOMPARE(object->property("test_false1").toBool(), false);
2973     QCOMPARE(object->property("test_false2").toBool(), false);
2974     QCOMPARE(object->property("test_false3").toBool(), false);
2975
2976     delete object;
2977 }
2978
2979 // Test that assigning a null object works 
2980 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
2981 void tst_qdeclarativeecmascript::nullObjectBinding()
2982 {
2983     QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
2984
2985     QObject *object = component.create();
2986     QVERIFY(object != 0);
2987
2988     QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
2989
2990     delete object;
2991 }
2992
2993 // Test that bindings don't evaluate once the engine has been destroyed
2994 void tst_qdeclarativeecmascript::deletedEngine()
2995 {
2996     QDeclarativeEngine *engine = new QDeclarativeEngine;
2997     QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
2998
2999     QObject *object = component.create();
3000     QVERIFY(object != 0);
3001
3002     QCOMPARE(object->property("a").toInt(), 39);
3003     object->setProperty("b", QVariant(9));
3004     QCOMPARE(object->property("a").toInt(), 117);
3005
3006     delete engine;
3007
3008     QCOMPARE(object->property("a").toInt(), 117);
3009     object->setProperty("b", QVariant(10));
3010     QCOMPARE(object->property("a").toInt(), 117);
3011
3012     delete object;
3013 }
3014
3015 // Test the crashing part of QTBUG-9705
3016 void tst_qdeclarativeecmascript::libraryScriptAssert()
3017 {
3018     QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3019
3020     QObject *object = component.create();
3021     QVERIFY(object != 0);
3022
3023     delete object;
3024 }
3025
3026 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3027 {
3028     QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3029
3030     QObject *object = component.create();
3031     QVERIFY(object != 0);
3032
3033     QCOMPARE(object->property("test1").toInt(), 10);
3034     QCOMPARE(object->property("test2").toInt(), 11);
3035
3036     object->setProperty("runTest", true);
3037
3038     QCOMPARE(object->property("test1"), QVariant());
3039     QCOMPARE(object->property("test2"), QVariant());
3040
3041
3042     delete object;
3043 }
3044
3045 void tst_qdeclarativeecmascript::qtbug_9792()
3046 {
3047     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3048
3049     QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3050
3051     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3052     QVERIFY(object != 0);
3053
3054     QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3055     object->basicSignal();
3056
3057     delete context;
3058
3059     transientErrorsMsgCount = 0;
3060     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3061
3062     object->basicSignal();
3063     
3064     qInstallMsgHandler(old);
3065
3066     QCOMPARE(transientErrorsMsgCount, 0);
3067
3068     delete object;
3069 }
3070
3071 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3072 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3073 {
3074     QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3075
3076     QObject *o = component.create();
3077     QVERIFY(o != 0);
3078
3079     QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3080     QVERIFY(nested != 0);
3081
3082     QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3083
3084     delete nested;
3085     nested = qvariant_cast<QObject *>(o->property("object"));
3086     QVERIFY(nested == 0);
3087
3088     // If the bug is present, the next line will crash
3089     delete o;
3090 }
3091
3092 // Test that we shut down without stupid warnings
3093 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3094 {
3095     {
3096     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.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     {
3112     QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3113
3114     QObject *o = component.create();
3115
3116     transientErrorsMsgCount = 0;
3117     QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3118
3119     delete o;
3120
3121     qInstallMsgHandler(old);
3122
3123     QCOMPARE(transientErrorsMsgCount, 0);
3124     }
3125 }
3126
3127 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3128 {
3129     {
3130     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3131
3132     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3133     QVERIFY(o != 0);
3134
3135     QVERIFY(o->objectProperty() != 0);
3136
3137     o->setProperty("runTest", true);
3138
3139     QVERIFY(o->objectProperty() == 0);
3140
3141     delete o;
3142     }
3143
3144     {
3145     QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3146
3147     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3148     QVERIFY(o != 0);
3149
3150     QVERIFY(o->objectProperty() == 0);
3151
3152     delete o;
3153     }
3154 }
3155
3156 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3157 {
3158     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3159
3160     QString url = component.url().toString();
3161     QString warning = url + ":4: Unable to assign a function to a property.";
3162     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3163     
3164     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3165     QVERIFY(o != 0);
3166
3167     QVERIFY(!o->property("a").isValid());
3168
3169     delete o;
3170 }
3171
3172 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3173 {
3174     QFETCH(QString, triggerProperty);
3175
3176     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3177     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3178
3179     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3180     QVERIFY(o != 0);
3181     QVERIFY(!o->property("a").isValid());
3182
3183     o->setProperty("aNumber", QVariant(5));
3184     o->setProperty(triggerProperty.toUtf8().constData(), true);
3185     QCOMPARE(o->property("a"), QVariant(50));
3186
3187     o->setProperty("aNumber", QVariant(10));
3188     QCOMPARE(o->property("a"), QVariant(100));
3189
3190     delete o;
3191 }
3192
3193 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3194 {
3195     QTest::addColumn<QString>("triggerProperty");
3196
3197     QTest::newRow("assign to property") << "assignToProperty";
3198     QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3199
3200     QTest::newRow("assign to value type") << "assignToValueType";
3201
3202     QTest::newRow("use 'this'") << "assignWithThis";
3203     QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3204 }
3205
3206 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3207 {
3208     QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3209     QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3210
3211     MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3212     QVERIFY(o != 0);
3213     QVERIFY(!o->property("a").isValid());
3214
3215     o->setProperty("assignFuncWithoutReturn", true);
3216     QVERIFY(!o->property("a").isValid());
3217
3218     QString url = component.url().toString();
3219     QString warning = url + ":67: Unable to assign QString to int";
3220     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3221     o->setProperty("assignWrongType", true);
3222
3223     warning = url + ":71: Unable to assign QString to int";
3224     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3225     o->setProperty("assignWrongTypeToValueType", true);
3226
3227     delete o;
3228 }
3229
3230 void tst_qdeclarativeecmascript::eval()
3231 {
3232     QDeclarativeComponent component(&engine, TEST_FILE("eval.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     QCOMPARE(o->property("test4").toBool(), true);
3241     QCOMPARE(o->property("test5").toBool(), true);
3242
3243     delete o;
3244 }
3245
3246 void tst_qdeclarativeecmascript::function()
3247 {
3248     QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3249
3250     QObject *o = component.create();
3251     QVERIFY(o != 0);
3252
3253     QCOMPARE(o->property("test1").toBool(), true);
3254     QCOMPARE(o->property("test2").toBool(), true);
3255     QCOMPARE(o->property("test3").toBool(), true);
3256
3257     delete o;
3258 }
3259
3260 // Test the "Qt.include" method
3261 void tst_qdeclarativeecmascript::include()
3262 {
3263     // Non-library relative include
3264     {
3265     QDeclarativeComponent component(&engine, TEST_FILE("include.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     // Library relative include
3280     {
3281     QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3282     QObject *o = component.create();
3283     QVERIFY(o != 0);
3284
3285     QCOMPARE(o->property("test0").toInt(), 99);
3286     QCOMPARE(o->property("test1").toBool(), true);
3287     QCOMPARE(o->property("test2").toBool(), true);
3288     QCOMPARE(o->property("test2_1").toBool(), true);
3289     QCOMPARE(o->property("test3").toBool(), true);
3290     QCOMPARE(o->property("test3_1").toBool(), true);
3291
3292     delete o;
3293     }
3294
3295     // Callback
3296     {
3297     QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3298     QObject *o = component.create();
3299     QVERIFY(o != 0);
3300
3301     QCOMPARE(o->property("test1").toBool(), true);
3302     QCOMPARE(o->property("test2").toBool(), true);
3303     QCOMPARE(o->property("test3").toBool(), true);
3304     QCOMPARE(o->property("test4").toBool(), true);
3305     QCOMPARE(o->property("test5").toBool(), true);
3306     QCOMPARE(o->property("test6").toBool(), true);
3307
3308     delete o;
3309     }
3310
3311     // Including file with ".pragma library"
3312     {
3313     QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3314     QObject *o = component.create();
3315     QVERIFY(o != 0);
3316     QCOMPARE(o->property("test1").toInt(), 100);
3317
3318     delete o;
3319     }
3320
3321     // Remote - success
3322     {
3323     TestHTTPServer server(8111);
3324     QVERIFY(server.isValid());
3325     server.serveDirectory(SRCDIR "/data");
3326
3327     QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3328     QObject *o = component.create();
3329     QVERIFY(o != 0);
3330
3331     QTRY_VERIFY(o->property("done").toBool() == true);
3332     QTRY_VERIFY(o->property("done2").toBool() == true);
3333
3334     QCOMPARE(o->property("test1").toBool(), true);
3335     QCOMPARE(o->property("test2").toBool(), true);
3336     QCOMPARE(o->property("test3").toBool(), true);
3337     QCOMPARE(o->property("test4").toBool(), true);
3338     QCOMPARE(o->property("test5").toBool(), true);
3339
3340     QCOMPARE(o->property("test6").toBool(), true);
3341     QCOMPARE(o->property("test7").toBool(), true);
3342     QCOMPARE(o->property("test8").toBool(), true);
3343     QCOMPARE(o->property("test9").toBool(), true);
3344     QCOMPARE(o->property("test10").toBool(), true);
3345
3346     delete o;
3347     }
3348
3349     // Remote - error
3350     {
3351     TestHTTPServer server(8111);
3352     QVERIFY(server.isValid());
3353     server.serveDirectory(SRCDIR "/data");
3354
3355     QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3356     QObject *o = component.create();
3357     QVERIFY(o != 0);
3358
3359     QTRY_VERIFY(o->property("done").toBool() == true);
3360
3361     QCOMPARE(o->property("test1").toBool(), true);
3362     QCOMPARE(o->property("test2").toBool(), true);
3363     QCOMPARE(o->property("test3").toBool(), true);
3364
3365     delete o;
3366     }
3367 }
3368
3369 void tst_qdeclarativeecmascript::qtbug_10696()
3370 {
3371     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3372     QObject *o = component.create();
3373     QVERIFY(o != 0);
3374     delete o;
3375 }
3376
3377 void tst_qdeclarativeecmascript::qtbug_11606()
3378 {
3379     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3380     QObject *o = component.create();
3381     QVERIFY(o != 0);
3382     QCOMPARE(o->property("test").toBool(), true);
3383     delete o;
3384 }
3385
3386 void tst_qdeclarativeecmascript::qtbug_11600()
3387 {
3388     QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3389     QObject *o = component.create();
3390     QVERIFY(o != 0);
3391     QCOMPARE(o->property("test").toBool(), true);
3392     delete o;
3393 }
3394
3395 // Reading and writing non-scriptable properties should fail
3396 void tst_qdeclarativeecmascript::nonscriptable()
3397 {
3398     QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3399     QObject *o = component.create();
3400     QVERIFY(o != 0);
3401     QCOMPARE(o->property("readOk").toBool(), true);
3402     QCOMPARE(o->property("writeOk").toBool(), true);
3403     delete o;
3404 }
3405
3406 // deleteLater() should not be callable from QML
3407 void tst_qdeclarativeecmascript::deleteLater()
3408 {
3409     QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3410     QObject *o = component.create();
3411     QVERIFY(o != 0);
3412     QCOMPARE(o->property("test").toBool(), true);
3413     delete o;
3414 }
3415
3416 void tst_qdeclarativeecmascript::in()
3417 {
3418     QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3419     QObject *o = component.create();
3420     QVERIFY(o != 0);
3421     QCOMPARE(o->property("test1").toBool(), true);
3422     QCOMPARE(o->property("test2").toBool(), true);
3423     delete o;
3424 }
3425
3426 void tst_qdeclarativeecmascript::sharedAttachedObject()
3427 {
3428     QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3429     QObject *o = component.create();
3430     QVERIFY(o != 0);
3431     QCOMPARE(o->property("test1").toBool(), true);
3432     QCOMPARE(o->property("test2").toBool(), true);
3433     delete o;
3434 }
3435
3436 // QTBUG-13999
3437 void tst_qdeclarativeecmascript::objectName()
3438 {
3439     QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3440     QObject *o = component.create();
3441     QVERIFY(o != 0);
3442
3443     QCOMPARE(o->property("test1").toString(), QString("hello"));
3444     QCOMPARE(o->property("test2").toString(), QString("ell"));
3445
3446     o->setObjectName("world");
3447
3448     QCOMPARE(o->property("test1").toString(), QString("world"));
3449     QCOMPARE(o->property("test2").toString(), QString("orl"));
3450
3451     delete o;
3452 }
3453
3454 void tst_qdeclarativeecmascript::writeRemovesBinding()
3455 {
3456     QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3457     QObject *o = component.create();
3458     QVERIFY(o != 0);
3459
3460     QCOMPARE(o->property("test").toBool(), true);
3461
3462     delete o;
3463 }
3464
3465 // Test bindings assigned to alias properties actually assign to the alias' target
3466 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3467 {
3468     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3469     QObject *o = component.create();
3470     QVERIFY(o != 0);
3471
3472     QCOMPARE(o->property("test").toBool(), true);
3473
3474     delete o;
3475 }
3476
3477 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3478 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3479 {
3480     { 
3481     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3482     QObject *o = component.create();
3483     QVERIFY(o != 0);
3484
3485     QCOMPARE(o->property("test").toBool(), true);
3486
3487     delete o;
3488     }
3489
3490     {
3491     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
3492     QObject *o = component.create();
3493     QVERIFY(o != 0);
3494
3495     QCOMPARE(o->property("test").toBool(), true);
3496
3497     delete o;
3498     }
3499
3500     {
3501     QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
3502     QObject *o = component.create();
3503     QVERIFY(o != 0);
3504
3505     QCOMPARE(o->property("test").toBool(), true);
3506
3507     delete o;
3508     }
3509 }
3510
3511 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
3512 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
3513 {
3514     {
3515     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
3516     QObject *o = component.create();
3517     QVERIFY(o != 0);
3518
3519     QCOMPARE(o->property("test").toBool(), true);
3520
3521     delete o;
3522     }
3523
3524     {
3525     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
3526     QObject *o = component.create();
3527     QVERIFY(o != 0);
3528
3529     QCOMPARE(o->property("test").toBool(), true);
3530
3531     delete o;
3532     }
3533
3534     {
3535     QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
3536     QObject *o = component.create();
3537     QVERIFY(o != 0);
3538
3539     QCOMPARE(o->property("test").toBool(), true);
3540
3541     delete o;
3542     }
3543 }
3544
3545 // Allow an alais to a composite element
3546 // QTBUG-20200
3547 void tst_qdeclarativeecmascript::aliasToCompositeElement()
3548 {
3549     QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
3550
3551     QObject *object = component.create();
3552     QVERIFY(object != 0);
3553
3554     delete object;
3555 }
3556
3557 void tst_qdeclarativeecmascript::revisionErrors()
3558 {
3559     {
3560         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
3561         QString url = component.url().toString();
3562
3563         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3564         QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
3565         QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
3566
3567         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3568         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3569         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3570         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3571         QVERIFY(object != 0);
3572         delete object;
3573     }
3574     {
3575         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
3576         QString url = component.url().toString();
3577
3578         // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
3579         // method2, prop2 from MyRevisionedClass not available
3580         // method4, prop4 from MyRevisionedSubclass not available
3581         QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3582         QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
3583         QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
3584         QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
3585         QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
3586
3587         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3588         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3589         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3590         QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
3591         QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
3592         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3593         QVERIFY(object != 0);
3594         delete object;
3595     }
3596     {
3597         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
3598         QString url = component.url().toString();
3599
3600         // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
3601         // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
3602         QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
3603         QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
3604         QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
3605         QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3606         QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3607         QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3608         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3609         QVERIFY(object != 0);
3610         delete object;
3611     }
3612 }
3613
3614 void tst_qdeclarativeecmascript::revision()
3615 {
3616     {
3617         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
3618         QString url = component.url().toString();
3619
3620         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3621         QVERIFY(object != 0);
3622         delete object;
3623     }
3624     {
3625         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
3626         QString url = component.url().toString();
3627
3628         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3629         QVERIFY(object != 0);
3630         delete object;
3631     }
3632     {
3633         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
3634         QString url = component.url().toString();
3635
3636         MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3637         QVERIFY(object != 0);
3638         delete object;
3639     }
3640     // Test that non-root classes can resolve revisioned methods
3641     {
3642         QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
3643
3644         QObject *object = component.create();
3645         QVERIFY(object != 0);
3646         QCOMPARE(object->property("test").toReal(), 11.);
3647         delete object;
3648     }
3649 }
3650
3651 void tst_qdeclarativeecmascript::realToInt()
3652 {
3653     QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
3654     MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
3655     QVERIFY(object != 0);
3656
3657     QMetaObject::invokeMethod(object, "test1");
3658     QCOMPARE(object->value(), int(4));
3659     QMetaObject::invokeMethod(object, "test2");
3660     QCOMPARE(object->value(), int(8));
3661 }
3662 void tst_qdeclarativeecmascript::dynamicString()
3663 {
3664     QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
3665     QObject *object = component.create();
3666     QVERIFY(object != 0);
3667     QCOMPARE(object->property("stringProperty").toString(),
3668              QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
3669 }
3670
3671 QTEST_MAIN(tst_qdeclarativeecmascript)
3672
3673 #include "tst_qdeclarativeecmascript.moc"