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