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