1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
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/qdeclarativevmemetaobject_p.h>
53 #include <private/qv4compiler_p.h>
54 #include "testtypes.h"
55 #include "testhttpserver.h"
56 #include "../../shared/util.h"
59 This test covers evaluation of ECMAScript expressions and bindings from within
60 QML. This does not include static QML language issues.
62 Static QML language issues are covered in qmllanguage
64 inline QUrl TEST_FILE(const QString &filename)
66 return QUrl::fromLocalFile(TESTDATA(filename));
69 inline QUrl TEST_FILE(const char *filename)
71 return TEST_FILE(QLatin1String(filename));
74 class tst_qdeclarativeecmascript : public QObject
78 tst_qdeclarativeecmascript() {}
82 void assignBasicTypes();
83 void idShortcutInvalidates();
84 void boolPropertiesEvaluateAsBool();
86 void signalAssignment();
88 void basicExpressions();
89 void basicExpressions_data();
90 void arrayExpressions();
91 void contextPropertiesTriggerReeval();
92 void objectPropertiesTriggerReeval();
93 void deferredProperties();
94 void deferredPropertiesErrors();
95 void extensionObjects();
96 void overrideExtensionProperties();
97 void attachedProperties();
99 void valueTypeFunctions();
100 void constantsOverrideBindings();
101 void outerBindingOverridesInnerBinding();
102 void aliasPropertyAndBinding();
103 void aliasPropertyReset();
104 void nonExistentAttachedObject();
107 void signalParameterTypes();
108 void objectsCompareAsEqual();
109 void dynamicCreation_data();
110 void dynamicCreation();
111 void dynamicDestruction();
112 void objectToString();
113 void objectHasOwnProperty();
114 void selfDeletingBinding();
115 void extendedObjectPropertyLookup();
116 void extendedObjectPropertyLookup2();
118 void functionErrors();
119 void propertyAssignmentErrors();
120 void signalTriggeredBindings();
121 void listProperties();
122 void exceptionClearsOnReeval();
123 void exceptionSlotProducesWarning();
124 void exceptionBindingProducesWarning();
125 void transientErrors();
126 void shutdownErrors();
127 void compositePropertyType();
129 void undefinedResetsProperty();
130 void listToVariant();
131 void listAssignment();
132 void multiEngineObject();
133 void deletedObject();
134 void attachedPropertyScope();
135 void scriptConnect();
136 void scriptDisconnect();
138 void cppOwnershipReturnValue();
139 void ownershipCustomReturnValue();
140 void qlistqobjectMethods();
141 void strictlyEquals();
143 void numberAssignment();
144 void propertySplicing();
145 void signalWithUnknownTypes();
146 void signalWithJSValueInVariant_data();
147 void signalWithJSValueInVariant();
148 void signalWithJSValueInVariant_twoEngines_data();
149 void signalWithJSValueInVariant_twoEngines();
150 void signalWithQJSValue_data();
151 void signalWithQJSValue();
152 void moduleApi_data();
154 void importScripts_data();
155 void importScripts();
156 void scarceResources();
157 void scarceResources_data();
158 void scarceResources_other();
159 void propertyChangeSlots();
160 void propertyVar_data();
162 void propertyVarCpp();
163 void propertyVarOwnership();
164 void propertyVarImplicitOwnership();
165 void propertyVarReparent();
166 void propertyVarReparentNullContext();
167 void propertyVarCircular();
168 void propertyVarCircular2();
169 void propertyVarInheritance();
170 void propertyVarInheritance2();
171 void elementAssign();
172 void objectPassThroughSignals();
173 void objectConversion();
174 void booleanConversion();
175 void handleReferenceManagement();
177 void readonlyDeclaration();
178 void sequenceConversionRead();
179 void sequenceConversionWrite();
180 void sequenceConversionArray();
181 void sequenceConversionThreads();
182 void sequenceConversionBindings();
183 void sequenceConversionCopy();
184 void assignSequenceTypes();
190 void dynamicCreationCrash();
191 void dynamicCreationOwnership();
193 void nullObjectBinding();
194 void deletedEngine();
195 void libraryScriptAssert();
196 void variantsAssignedUndefined();
198 void qtcreatorbug_1289();
199 void noSpuriousWarningsAtShutdown();
200 void canAssignNullToQObject();
201 void functionAssignment_fromBinding();
202 void functionAssignment_fromJS();
203 void functionAssignment_fromJS_data();
204 void functionAssignmentfromJS_invalid();
211 void nonscriptable();
215 void sharedAttachedObject();
217 void writeRemovesBinding();
218 void aliasBindingsAssignCorrectly();
219 void aliasBindingsOverrideTarget();
220 void aliasWritesOverrideBindings();
221 void aliasToCompositeElement();
224 void dynamicString();
226 void signalHandlers();
227 void doubleEvaluate();
229 void nonNotifyable();
230 void deleteWhileBindingRunning();
231 void callQtInvokables();
232 void invokableObjectArg();
233 void invokableObjectRet();
236 void qtbug_22843_data();
238 void revisionErrors();
241 void automaticSemicolon();
242 void unaryExpression();
243 void switchStatement();
244 void withStatement();
248 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
249 QDeclarativeEngine engine;
252 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
254 void tst_qdeclarativeecmascript::assignBasicTypes()
257 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
258 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
259 QVERIFY(object != 0);
260 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
261 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
262 QCOMPARE(object->stringProperty(), QString("Hello World!"));
263 QCOMPARE(object->uintProperty(), uint(10));
264 QCOMPARE(object->intProperty(), -19);
265 QCOMPARE((float)object->realProperty(), float(23.2));
266 QCOMPARE((float)object->doubleProperty(), float(-19.75));
267 QCOMPARE((float)object->floatProperty(), float(8.5));
268 QCOMPARE(object->colorProperty(), QColor("red"));
269 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
270 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
271 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
272 QCOMPARE(object->pointProperty(), QPoint(99,13));
273 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
274 QCOMPARE(object->sizeProperty(), QSize(99, 13));
275 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
276 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
277 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
278 QCOMPARE(object->boolProperty(), true);
279 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
280 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
281 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
285 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
286 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
287 QVERIFY(object != 0);
288 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
289 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
290 QCOMPARE(object->stringProperty(), QString("Hello World!"));
291 QCOMPARE(object->uintProperty(), uint(10));
292 QCOMPARE(object->intProperty(), -19);
293 QCOMPARE((float)object->realProperty(), float(23.2));
294 QCOMPARE((float)object->doubleProperty(), float(-19.75));
295 QCOMPARE((float)object->floatProperty(), float(8.5));
296 QCOMPARE(object->colorProperty(), QColor("red"));
297 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
298 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
299 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
300 QCOMPARE(object->pointProperty(), QPoint(99,13));
301 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
302 QCOMPARE(object->sizeProperty(), QSize(99, 13));
303 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
304 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
305 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
306 QCOMPARE(object->boolProperty(), true);
307 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
308 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
309 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
314 void tst_qdeclarativeecmascript::idShortcutInvalidates()
317 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
318 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
319 QVERIFY(object != 0);
320 QVERIFY(object->objectProperty() != 0);
321 delete object->objectProperty();
322 QVERIFY(object->objectProperty() == 0);
327 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
328 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
329 QVERIFY(object != 0);
330 QVERIFY(object->objectProperty() != 0);
331 delete object->objectProperty();
332 QVERIFY(object->objectProperty() == 0);
337 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
340 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
341 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
342 QVERIFY(object != 0);
343 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
347 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
348 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
349 QVERIFY(object != 0);
350 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
355 void tst_qdeclarativeecmascript::signalAssignment()
358 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
359 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
360 QVERIFY(object != 0);
361 QCOMPARE(object->string(), QString());
362 emit object->basicSignal();
363 QCOMPARE(object->string(), QString("pass"));
368 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
369 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
370 QVERIFY(object != 0);
371 QCOMPARE(object->string(), QString());
372 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
373 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
378 void tst_qdeclarativeecmascript::methods()
381 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
382 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
383 QVERIFY(object != 0);
384 QCOMPARE(object->methodCalled(), false);
385 QCOMPARE(object->methodIntCalled(), false);
386 emit object->basicSignal();
387 QCOMPARE(object->methodCalled(), true);
388 QCOMPARE(object->methodIntCalled(), false);
393 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
394 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
395 QVERIFY(object != 0);
396 QCOMPARE(object->methodCalled(), false);
397 QCOMPARE(object->methodIntCalled(), false);
398 emit object->basicSignal();
399 QCOMPARE(object->methodCalled(), false);
400 QCOMPARE(object->methodIntCalled(), true);
405 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
406 QObject *object = component.create();
407 QVERIFY(object != 0);
408 QCOMPARE(object->property("test").toInt(), 19);
413 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
414 QObject *object = component.create();
415 QVERIFY(object != 0);
416 QCOMPARE(object->property("test").toInt(), 19);
417 QCOMPARE(object->property("test2").toInt(), 17);
418 QCOMPARE(object->property("test3").toInt(), 16);
423 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
424 QObject *object = component.create();
425 QVERIFY(object != 0);
426 QCOMPARE(object->property("test").toInt(), 9);
431 void tst_qdeclarativeecmascript::bindingLoop()
433 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
434 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
435 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
436 QObject *object = component.create();
437 QVERIFY(object != 0);
441 void tst_qdeclarativeecmascript::basicExpressions_data()
443 QTest::addColumn<QString>("expression");
444 QTest::addColumn<QVariant>("result");
445 QTest::addColumn<bool>("nest");
447 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
448 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
449 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
450 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
451 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
452 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
453 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
454 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
455 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
456 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
457 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
458 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
459 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
460 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
461 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
462 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
463 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
464 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
465 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
468 void tst_qdeclarativeecmascript::basicExpressions()
470 QFETCH(QString, expression);
471 QFETCH(QVariant, result);
477 MyDefaultObject1 default1;
478 MyDefaultObject3 default3;
479 object1.setStringProperty("Object1");
480 object2.setStringProperty("Object2");
481 object3.setStringProperty("Object3");
483 QDeclarativeContext context(engine.rootContext());
484 QDeclarativeContext nestedContext(&context);
486 context.setContextObject(&default1);
487 context.setContextProperty("a", QVariant(1944));
488 context.setContextProperty("b", QVariant("Milk"));
489 context.setContextProperty("object", &object1);
490 context.setContextProperty("objectOverride", &object2);
491 nestedContext.setContextObject(&default3);
492 nestedContext.setContextProperty("b", QVariant("Cow"));
493 nestedContext.setContextProperty("objectOverride", &object3);
494 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
496 MyExpression expr(nest?&nestedContext:&context, expression);
497 QCOMPARE(expr.evaluate(), result);
500 void tst_qdeclarativeecmascript::arrayExpressions()
506 QDeclarativeContext context(engine.rootContext());
507 context.setContextProperty("a", &obj1);
508 context.setContextProperty("b", &obj2);
509 context.setContextProperty("c", &obj3);
511 MyExpression expr(&context, "[a, b, c, 10]");
512 QVariant result = expr.evaluate();
513 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
514 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
515 QCOMPARE(list.count(), 4);
516 QCOMPARE(list.at(0), &obj1);
517 QCOMPARE(list.at(1), &obj2);
518 QCOMPARE(list.at(2), &obj3);
519 QCOMPARE(list.at(3), (QObject *)0);
522 // Tests that modifying a context property will reevaluate expressions
523 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
525 QDeclarativeContext context(engine.rootContext());
528 MyQmlObject *object3 = new MyQmlObject;
530 object1.setStringProperty("Hello");
531 object2.setStringProperty("World");
533 context.setContextProperty("testProp", QVariant(1));
534 context.setContextProperty("testObj", &object1);
535 context.setContextProperty("testObj2", object3);
538 MyExpression expr(&context, "testProp + 1");
539 QCOMPARE(expr.changed, false);
540 QCOMPARE(expr.evaluate(), QVariant(2));
542 context.setContextProperty("testProp", QVariant(2));
543 QCOMPARE(expr.changed, true);
544 QCOMPARE(expr.evaluate(), QVariant(3));
548 MyExpression expr(&context, "testProp + testProp + testProp");
549 QCOMPARE(expr.changed, false);
550 QCOMPARE(expr.evaluate(), QVariant(6));
552 context.setContextProperty("testProp", QVariant(4));
553 QCOMPARE(expr.changed, true);
554 QCOMPARE(expr.evaluate(), QVariant(12));
558 MyExpression expr(&context, "testObj.stringProperty");
559 QCOMPARE(expr.changed, false);
560 QCOMPARE(expr.evaluate(), QVariant("Hello"));
562 context.setContextProperty("testObj", &object2);
563 QCOMPARE(expr.changed, true);
564 QCOMPARE(expr.evaluate(), QVariant("World"));
568 MyExpression expr(&context, "testObj.stringProperty /**/");
569 QCOMPARE(expr.changed, false);
570 QCOMPARE(expr.evaluate(), QVariant("World"));
572 context.setContextProperty("testObj", &object1);
573 QCOMPARE(expr.changed, true);
574 QCOMPARE(expr.evaluate(), QVariant("Hello"));
578 MyExpression expr(&context, "testObj2");
579 QCOMPARE(expr.changed, false);
580 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
586 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
588 QDeclarativeContext context(engine.rootContext());
592 context.setContextProperty("testObj", &object1);
594 object1.setStringProperty(QLatin1String("Hello"));
595 object2.setStringProperty(QLatin1String("Dog"));
596 object3.setStringProperty(QLatin1String("Cat"));
599 MyExpression expr(&context, "testObj.stringProperty");
600 QCOMPARE(expr.changed, false);
601 QCOMPARE(expr.evaluate(), QVariant("Hello"));
603 object1.setStringProperty(QLatin1String("World"));
604 QCOMPARE(expr.changed, true);
605 QCOMPARE(expr.evaluate(), QVariant("World"));
609 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
610 QCOMPARE(expr.changed, false);
611 QCOMPARE(expr.evaluate(), QVariant());
613 object1.setObjectProperty(&object2);
614 QCOMPARE(expr.changed, true);
615 expr.changed = false;
616 QCOMPARE(expr.evaluate(), QVariant("Dog"));
618 object1.setObjectProperty(&object3);
619 QCOMPARE(expr.changed, true);
620 expr.changed = false;
621 QCOMPARE(expr.evaluate(), QVariant("Cat"));
623 object1.setObjectProperty(0);
624 QCOMPARE(expr.changed, true);
625 expr.changed = false;
626 QCOMPARE(expr.evaluate(), QVariant());
628 object1.setObjectProperty(&object3);
629 QCOMPARE(expr.changed, true);
630 expr.changed = false;
631 QCOMPARE(expr.evaluate(), QVariant("Cat"));
633 object3.setStringProperty("Donkey");
634 QCOMPARE(expr.changed, true);
635 expr.changed = false;
636 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
640 void tst_qdeclarativeecmascript::deferredProperties()
642 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
643 MyDeferredObject *object =
644 qobject_cast<MyDeferredObject *>(component.create());
645 QVERIFY(object != 0);
646 QCOMPARE(object->value(), 0);
647 QVERIFY(object->objectProperty() == 0);
648 QVERIFY(object->objectProperty2() != 0);
649 qmlExecuteDeferred(object);
650 QCOMPARE(object->value(), 10);
651 QVERIFY(object->objectProperty() != 0);
652 MyQmlObject *qmlObject =
653 qobject_cast<MyQmlObject *>(object->objectProperty());
654 QVERIFY(qmlObject != 0);
655 QCOMPARE(qmlObject->value(), 10);
656 object->setValue(19);
657 QCOMPARE(qmlObject->value(), 19);
662 // Check errors on deferred properties are correctly emitted
663 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
665 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
666 MyDeferredObject *object =
667 qobject_cast<MyDeferredObject *>(component.create());
668 QVERIFY(object != 0);
669 QCOMPARE(object->value(), 0);
670 QVERIFY(object->objectProperty() == 0);
671 QVERIFY(object->objectProperty2() == 0);
673 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
674 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
676 qmlExecuteDeferred(object);
681 void tst_qdeclarativeecmascript::extensionObjects()
683 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
684 MyExtendedObject *object =
685 qobject_cast<MyExtendedObject *>(component.create());
686 QVERIFY(object != 0);
687 QCOMPARE(object->baseProperty(), 13);
688 QCOMPARE(object->coreProperty(), 9);
689 object->setProperty("extendedProperty", QVariant(11));
690 object->setProperty("baseExtendedProperty", QVariant(92));
691 QCOMPARE(object->coreProperty(), 11);
692 QCOMPARE(object->baseProperty(), 92);
694 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
696 QCOMPARE(nested->baseProperty(), 13);
697 QCOMPARE(nested->coreProperty(), 9);
698 nested->setProperty("extendedProperty", QVariant(11));
699 nested->setProperty("baseExtendedProperty", QVariant(92));
700 QCOMPARE(nested->coreProperty(), 11);
701 QCOMPARE(nested->baseProperty(), 92);
706 void tst_qdeclarativeecmascript::overrideExtensionProperties()
708 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
709 OverrideDefaultPropertyObject *object =
710 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
711 QVERIFY(object != 0);
712 QVERIFY(object->secondProperty() != 0);
713 QVERIFY(object->firstProperty() == 0);
718 void tst_qdeclarativeecmascript::attachedProperties()
721 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
722 QObject *object = component.create();
723 QVERIFY(object != 0);
724 QCOMPARE(object->property("a").toInt(), 19);
725 QCOMPARE(object->property("b").toInt(), 19);
726 QCOMPARE(object->property("c").toInt(), 19);
727 QCOMPARE(object->property("d").toInt(), 19);
732 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
733 QObject *object = component.create();
734 QVERIFY(object != 0);
735 QCOMPARE(object->property("a").toInt(), 26);
736 QCOMPARE(object->property("b").toInt(), 26);
737 QCOMPARE(object->property("c").toInt(), 26);
738 QCOMPARE(object->property("d").toInt(), 26);
744 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
745 QObject *object = component.create();
746 QVERIFY(object != 0);
748 QMetaObject::invokeMethod(object, "writeValue2");
750 MyQmlAttachedObject *attached =
751 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
752 QVERIFY(attached != 0);
754 QCOMPARE(attached->value2(), 9);
759 void tst_qdeclarativeecmascript::enums()
763 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
764 QObject *object = component.create();
765 QVERIFY(object != 0);
767 QCOMPARE(object->property("a").toInt(), 0);
768 QCOMPARE(object->property("b").toInt(), 1);
769 QCOMPARE(object->property("c").toInt(), 2);
770 QCOMPARE(object->property("d").toInt(), 3);
771 QCOMPARE(object->property("e").toInt(), 0);
772 QCOMPARE(object->property("f").toInt(), 1);
773 QCOMPARE(object->property("g").toInt(), 2);
774 QCOMPARE(object->property("h").toInt(), 3);
775 QCOMPARE(object->property("i").toInt(), 19);
776 QCOMPARE(object->property("j").toInt(), 19);
780 // Non-existent enums
782 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
784 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
785 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
786 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
787 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
789 QObject *object = component.create();
790 QVERIFY(object != 0);
791 QCOMPARE(object->property("a").toInt(), 0);
792 QCOMPARE(object->property("b").toInt(), 0);
798 void tst_qdeclarativeecmascript::valueTypeFunctions()
800 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
801 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
803 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
804 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
810 Tests that writing a constant to a property with a binding on it disables the
813 void tst_qdeclarativeecmascript::constantsOverrideBindings()
817 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
818 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
819 QVERIFY(object != 0);
821 QCOMPARE(object->property("c2").toInt(), 0);
822 object->setProperty("c1", QVariant(9));
823 QCOMPARE(object->property("c2").toInt(), 9);
825 emit object->basicSignal();
827 QCOMPARE(object->property("c2").toInt(), 13);
828 object->setProperty("c1", QVariant(8));
829 QCOMPARE(object->property("c2").toInt(), 13);
834 // During construction
836 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
837 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
838 QVERIFY(object != 0);
840 QCOMPARE(object->property("c1").toInt(), 0);
841 QCOMPARE(object->property("c2").toInt(), 10);
842 object->setProperty("c1", QVariant(9));
843 QCOMPARE(object->property("c1").toInt(), 9);
844 QCOMPARE(object->property("c2").toInt(), 10);
852 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
853 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
854 QVERIFY(object != 0);
856 QCOMPARE(object->property("c2").toInt(), 0);
857 object->setProperty("c1", QVariant(9));
858 QCOMPARE(object->property("c2").toInt(), 9);
860 object->setProperty("c2", QVariant(13));
861 QCOMPARE(object->property("c2").toInt(), 13);
862 object->setProperty("c1", QVariant(7));
863 QCOMPARE(object->property("c1").toInt(), 7);
864 QCOMPARE(object->property("c2").toInt(), 13);
872 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
873 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
874 QVERIFY(object != 0);
876 QCOMPARE(object->property("c1").toInt(), 0);
877 QCOMPARE(object->property("c3").toInt(), 10);
878 object->setProperty("c1", QVariant(9));
879 QCOMPARE(object->property("c1").toInt(), 9);
880 QCOMPARE(object->property("c3").toInt(), 10);
887 Tests that assigning a binding to a property that already has a binding causes
888 the original binding to be disabled.
890 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
892 QDeclarativeComponent component(&engine,
893 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
894 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
895 QVERIFY(object != 0);
897 QCOMPARE(object->property("c1").toInt(), 0);
898 QCOMPARE(object->property("c2").toInt(), 0);
899 QCOMPARE(object->property("c3").toInt(), 0);
901 object->setProperty("c1", QVariant(9));
902 QCOMPARE(object->property("c1").toInt(), 9);
903 QCOMPARE(object->property("c2").toInt(), 0);
904 QCOMPARE(object->property("c3").toInt(), 0);
906 object->setProperty("c3", QVariant(8));
907 QCOMPARE(object->property("c1").toInt(), 9);
908 QCOMPARE(object->property("c2").toInt(), 8);
909 QCOMPARE(object->property("c3").toInt(), 8);
915 Access a non-existent attached object.
917 Tests for a regression where this used to crash.
919 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
921 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
923 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
924 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
926 QObject *object = component.create();
927 QVERIFY(object != 0);
932 void tst_qdeclarativeecmascript::scope()
935 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
936 QObject *object = component.create();
937 QVERIFY(object != 0);
939 QCOMPARE(object->property("test1").toInt(), 1);
940 QCOMPARE(object->property("test2").toInt(), 2);
941 QCOMPARE(object->property("test3").toString(), QString("1Test"));
942 QCOMPARE(object->property("test4").toString(), QString("2Test"));
943 QCOMPARE(object->property("test5").toInt(), 1);
944 QCOMPARE(object->property("test6").toInt(), 1);
945 QCOMPARE(object->property("test7").toInt(), 2);
946 QCOMPARE(object->property("test8").toInt(), 2);
947 QCOMPARE(object->property("test9").toInt(), 1);
948 QCOMPARE(object->property("test10").toInt(), 3);
954 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
955 QObject *object = component.create();
956 QVERIFY(object != 0);
958 QCOMPARE(object->property("test1").toInt(), 19);
959 QCOMPARE(object->property("test2").toInt(), 19);
960 QCOMPARE(object->property("test3").toInt(), 14);
961 QCOMPARE(object->property("test4").toInt(), 14);
962 QCOMPARE(object->property("test5").toInt(), 24);
963 QCOMPARE(object->property("test6").toInt(), 24);
969 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
970 QObject *object = component.create();
971 QVERIFY(object != 0);
973 QCOMPARE(object->property("test1").toBool(), true);
974 QCOMPARE(object->property("test2").toBool(), true);
975 QCOMPARE(object->property("test3").toBool(), true);
980 // Signal argument scope
982 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
983 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
984 QVERIFY(object != 0);
986 QCOMPARE(object->property("test").toInt(), 0);
987 QCOMPARE(object->property("test2").toString(), QString());
989 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
991 QCOMPARE(object->property("test").toInt(), 13);
992 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
998 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
999 QObject *object = component.create();
1000 QVERIFY(object != 0);
1002 QCOMPARE(object->property("test1").toBool(), true);
1003 QCOMPARE(object->property("test2").toBool(), true);
1009 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
1010 QObject *object = component.create();
1011 QVERIFY(object != 0);
1013 QCOMPARE(object->property("test").toBool(), true);
1019 // In 4.7, non-library javascript files that had no imports shared the imports of their
1020 // importing context
1021 void tst_qdeclarativeecmascript::importScope()
1023 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1024 QObject *o = component.create();
1027 QCOMPARE(o->property("test").toInt(), 240);
1033 Tests that "any" type passes through a synthesized signal parameter. This
1034 is essentially a test of QDeclarativeMetaType::copy()
1036 void tst_qdeclarativeecmascript::signalParameterTypes()
1038 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1039 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1040 QVERIFY(object != 0);
1042 emit object->basicSignal();
1044 QCOMPARE(object->property("intProperty").toInt(), 10);
1045 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1046 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1047 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1048 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1049 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1055 Test that two JS objects for the same QObject compare as equal.
1057 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1059 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1060 QObject *object = component.create();
1061 QVERIFY(object != 0);
1063 QCOMPARE(object->property("test1").toBool(), true);
1064 QCOMPARE(object->property("test2").toBool(), true);
1065 QCOMPARE(object->property("test3").toBool(), true);
1066 QCOMPARE(object->property("test4").toBool(), true);
1067 QCOMPARE(object->property("test5").toBool(), true);
1073 Confirm bindings and alias properties can coexist.
1075 Tests for a regression where the binding would not reevaluate.
1077 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1079 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1080 QObject *object = component.create();
1081 QVERIFY(object != 0);
1083 QCOMPARE(object->property("c2").toInt(), 3);
1084 QCOMPARE(object->property("c3").toInt(), 3);
1086 object->setProperty("c2", QVariant(19));
1088 QCOMPARE(object->property("c2").toInt(), 19);
1089 QCOMPARE(object->property("c3").toInt(), 19);
1095 Ensure that we can write undefined value to an alias property,
1096 and that the aliased property is reset correctly if possible.
1098 void tst_qdeclarativeecmascript::aliasPropertyReset()
1100 QObject *object = 0;
1102 // test that a manual write (of undefined) to a resettable aliased property succeeds
1103 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1104 object = c1.create();
1105 QVERIFY(object != 0);
1106 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1107 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1108 QMetaObject::invokeMethod(object, "resetAliased");
1109 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1110 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1113 // test that a manual write (of undefined) to a resettable alias property succeeds
1114 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1115 object = c2.create();
1116 QVERIFY(object != 0);
1117 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1118 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1119 QMetaObject::invokeMethod(object, "resetAlias");
1120 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1121 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1124 // test that an alias to a bound property works correctly
1125 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1126 object = c3.create();
1127 QVERIFY(object != 0);
1128 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1129 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1130 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1131 QMetaObject::invokeMethod(object, "resetAlias");
1132 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1133 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1134 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1137 // test that a manual write (of undefined) to a resettable alias property
1138 // whose aliased property's object has been deleted, does not crash.
1139 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1140 object = c4.create();
1141 QVERIFY(object != 0);
1142 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1143 QObject *loader = object->findChild<QObject*>("loader");
1144 QVERIFY(loader != 0);
1146 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1147 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1148 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1149 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1150 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1153 // test that binding an alias property to an undefined value works correctly
1154 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1155 object = c5.create();
1156 QVERIFY(object != 0);
1157 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1160 // test that a manual write (of undefined) to a non-resettable property fails properly
1161 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1162 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1163 QDeclarativeComponent e1(&engine, url);
1164 object = e1.create();
1165 QVERIFY(object != 0);
1166 QCOMPARE(object->property("intAlias").value<int>(), 12);
1167 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1168 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1169 QMetaObject::invokeMethod(object, "resetAlias");
1170 QCOMPARE(object->property("intAlias").value<int>(), 12);
1171 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1175 void tst_qdeclarativeecmascript::dynamicCreation_data()
1177 QTest::addColumn<QString>("method");
1178 QTest::addColumn<QString>("createdName");
1180 QTest::newRow("One") << "createOne" << "objectOne";
1181 QTest::newRow("Two") << "createTwo" << "objectTwo";
1182 QTest::newRow("Three") << "createThree" << "objectThree";
1186 Test using createQmlObject to dynamically generate an item
1187 Also using createComponent is tested.
1189 void tst_qdeclarativeecmascript::dynamicCreation()
1191 QFETCH(QString, method);
1192 QFETCH(QString, createdName);
1194 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1195 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1196 QVERIFY(object != 0);
1198 QMetaObject::invokeMethod(object, method.toUtf8());
1199 QObject *created = object->objectProperty();
1201 QCOMPARE(created->objectName(), createdName);
1207 Tests the destroy function
1209 void tst_qdeclarativeecmascript::dynamicDestruction()
1212 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1213 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1214 QVERIFY(object != 0);
1215 QDeclarativeGuard<QObject> createdQmlObject = 0;
1217 QMetaObject::invokeMethod(object, "create");
1218 createdQmlObject = object->objectProperty();
1219 QVERIFY(createdQmlObject);
1220 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1222 QMetaObject::invokeMethod(object, "killOther");
1223 QVERIFY(createdQmlObject);
1224 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1225 QVERIFY(createdQmlObject);
1226 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1227 if (createdQmlObject) {
1229 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1232 QVERIFY(!createdQmlObject);
1234 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1235 QMetaObject::invokeMethod(object, "killMe");
1238 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1243 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1244 QObject *o = component.create();
1247 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1249 QMetaObject::invokeMethod(o, "create");
1251 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1253 QMetaObject::invokeMethod(o, "destroy");
1255 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1257 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1264 tests that id.toString() works
1266 void tst_qdeclarativeecmascript::objectToString()
1268 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1269 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1270 QVERIFY(object != 0);
1271 QMetaObject::invokeMethod(object, "testToString");
1272 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1273 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1279 tests that id.hasOwnProperty() works
1281 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1283 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1284 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1285 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1286 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1288 QDeclarativeComponent component(&engine, url);
1289 QObject *object = component.create();
1290 QVERIFY(object != 0);
1292 // test QObjects in QML
1293 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1294 QVERIFY(object->property("result").value<bool>() == true);
1295 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1296 QVERIFY(object->property("result").value<bool>() == false);
1298 // now test other types in QML
1299 QObject *child = object->findChild<QObject*>("typeObj");
1300 QVERIFY(child != 0);
1301 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1302 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1303 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1304 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1305 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1306 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1307 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1308 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1309 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1310 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1311 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1312 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1314 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1315 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1316 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1317 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1318 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1319 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1320 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1321 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1322 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1328 Tests bindings that indirectly cause their own deletion work.
1330 This test is best run under valgrind to ensure no invalid memory access occur.
1332 void tst_qdeclarativeecmascript::selfDeletingBinding()
1335 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1336 QObject *object = component.create();
1337 QVERIFY(object != 0);
1338 object->setProperty("triggerDelete", true);
1343 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1344 QObject *object = component.create();
1345 QVERIFY(object != 0);
1346 object->setProperty("triggerDelete", true);
1352 Test that extended object properties can be accessed.
1354 This test a regression where this used to crash. The issue was specificially
1355 for extended objects that did not include a synthesized meta object (so non-root
1356 and no synthesiszed properties).
1358 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1360 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1361 QObject *object = component.create();
1362 QVERIFY(object != 0);
1367 Test that extended object properties can be accessed correctly.
1369 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
1371 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup2.qml"));
1372 QObject *object = component.create();
1373 QVERIFY(object != 0);
1375 QVariant returnValue;
1376 QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
1377 QCOMPARE(returnValue.toInt(), 42);
1382 Test file/lineNumbers for binding/Script errors.
1384 void tst_qdeclarativeecmascript::scriptErrors()
1386 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1387 QString url = component.url().toString();
1389 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1390 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1391 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1392 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1393 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1394 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1395 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1396 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1398 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1399 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1400 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1401 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1402 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1403 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1404 QVERIFY(object != 0);
1406 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1407 emit object->basicSignal();
1409 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1410 emit object->anotherBasicSignal();
1412 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1413 emit object->thirdBasicSignal();
1419 Test file/lineNumbers for inline functions.
1421 void tst_qdeclarativeecmascript::functionErrors()
1423 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1424 QString url = component.url().toString();
1426 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1428 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1430 QObject *object = component.create();
1431 QVERIFY(object != 0);
1434 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1435 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
1436 url = componentTwo.url().toString();
1437 object = componentTwo.create();
1438 QVERIFY(object != 0);
1440 QString srpname = object->property("srp_name").toString();
1442 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1443 + QLatin1String(" is not a function");
1444 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1445 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1450 Test various errors that can occur when assigning a property from script
1452 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1454 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1456 QString url = component.url().toString();
1458 QObject *object = component.create();
1459 QVERIFY(object != 0);
1461 QCOMPARE(object->property("test1").toBool(), true);
1462 QCOMPARE(object->property("test2").toBool(), true);
1468 Test bindings still work when the reeval is triggered from within
1471 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1473 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1474 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1475 QVERIFY(object != 0);
1477 QCOMPARE(object->property("base").toReal(), 50.);
1478 QCOMPARE(object->property("test1").toReal(), 50.);
1479 QCOMPARE(object->property("test2").toReal(), 50.);
1481 object->basicSignal();
1483 QCOMPARE(object->property("base").toReal(), 200.);
1484 QCOMPARE(object->property("test1").toReal(), 200.);
1485 QCOMPARE(object->property("test2").toReal(), 200.);
1487 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1489 QCOMPARE(object->property("base").toReal(), 400.);
1490 QCOMPARE(object->property("test1").toReal(), 400.);
1491 QCOMPARE(object->property("test2").toReal(), 400.);
1497 Test that list properties can be iterated from ECMAScript
1499 void tst_qdeclarativeecmascript::listProperties()
1501 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1502 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1503 QVERIFY(object != 0);
1505 QCOMPARE(object->property("test1").toInt(), 21);
1506 QCOMPARE(object->property("test2").toInt(), 2);
1507 QCOMPARE(object->property("test3").toBool(), true);
1508 QCOMPARE(object->property("test4").toBool(), true);
1513 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1515 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1516 QString url = component.url().toString();
1518 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1520 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1521 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1522 QVERIFY(object != 0);
1524 QCOMPARE(object->property("test").toBool(), false);
1526 MyQmlObject object2;
1527 MyQmlObject object3;
1528 object2.setObjectProperty(&object3);
1529 object->setObjectProperty(&object2);
1531 QCOMPARE(object->property("test").toBool(), true);
1536 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1538 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1539 QString url = component.url().toString();
1541 QString warning = component.url().toString() + ":6: Error: JS exception";
1543 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1544 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1545 QVERIFY(object != 0);
1549 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1551 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1552 QString url = component.url().toString();
1554 QString warning = component.url().toString() + ":5: Error: JS exception";
1556 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1557 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1558 QVERIFY(object != 0);
1562 static int transientErrorsMsgCount = 0;
1563 static void transientErrorsMsgHandler(QtMsgType, const char *)
1565 ++transientErrorsMsgCount;
1568 // Check that transient binding errors are not displayed
1569 void tst_qdeclarativeecmascript::transientErrors()
1572 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1574 transientErrorsMsgCount = 0;
1575 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1577 QObject *object = component.create();
1578 QVERIFY(object != 0);
1580 qInstallMsgHandler(old);
1582 QCOMPARE(transientErrorsMsgCount, 0);
1587 // One binding erroring multiple times, but then resolving
1589 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1591 transientErrorsMsgCount = 0;
1592 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1594 QObject *object = component.create();
1595 QVERIFY(object != 0);
1597 qInstallMsgHandler(old);
1599 QCOMPARE(transientErrorsMsgCount, 0);
1605 // Check that errors during shutdown are minimized
1606 void tst_qdeclarativeecmascript::shutdownErrors()
1608 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1609 QObject *object = component.create();
1610 QVERIFY(object != 0);
1612 transientErrorsMsgCount = 0;
1613 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1617 qInstallMsgHandler(old);
1618 QCOMPARE(transientErrorsMsgCount, 0);
1621 void tst_qdeclarativeecmascript::compositePropertyType()
1623 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1625 QTest::ignoreMessage(QtDebugMsg, "hello world");
1626 QObject *object = qobject_cast<QObject *>(component.create());
1631 void tst_qdeclarativeecmascript::jsObject()
1633 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1634 QObject *object = component.create();
1635 QVERIFY(object != 0);
1637 QCOMPARE(object->property("test").toInt(), 92);
1642 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1645 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1646 QObject *object = component.create();
1647 QVERIFY(object != 0);
1649 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1651 object->setProperty("setUndefined", true);
1653 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1655 object->setProperty("setUndefined", false);
1657 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1662 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1663 QObject *object = component.create();
1664 QVERIFY(object != 0);
1666 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1668 QMetaObject::invokeMethod(object, "doReset");
1670 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1676 // Aliases to variant properties should work
1677 void tst_qdeclarativeecmascript::qtbug_22464()
1679 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1680 QObject *object = component.create();
1681 QVERIFY(object != 0);
1683 QCOMPARE(object->property("test").toBool(), true);
1688 void tst_qdeclarativeecmascript::qtbug_21580()
1690 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
1692 QObject *object = component.create();
1693 QVERIFY(object != 0);
1695 QCOMPARE(object->property("test").toBool(), true);
1701 void tst_qdeclarativeecmascript::bug1()
1703 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1704 QObject *object = component.create();
1705 QVERIFY(object != 0);
1707 QCOMPARE(object->property("test").toInt(), 14);
1709 object->setProperty("a", 11);
1711 QCOMPARE(object->property("test").toInt(), 3);
1713 object->setProperty("b", true);
1715 QCOMPARE(object->property("test").toInt(), 9);
1720 void tst_qdeclarativeecmascript::bug2()
1722 QDeclarativeComponent component(&engine);
1723 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1725 QObject *object = component.create();
1726 QVERIFY(object != 0);
1731 // Don't crash in createObject when the component has errors.
1732 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1734 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1735 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1736 QVERIFY(object != 0);
1738 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1739 QMetaObject::invokeMethod(object, "dontCrash");
1740 QObject *created = object->objectProperty();
1741 QVERIFY(created == 0);
1746 // ownership transferred to JS, ensure that GC runs the dtor
1747 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1750 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1752 // allow the engine to go out of scope too.
1754 QDeclarativeEngine dcoEngine;
1755 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1756 QObject *object = component.create();
1757 QVERIFY(object != 0);
1758 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1759 QVERIFY(mdcdo != 0);
1760 mdcdo->setDtorCount(&dtorCount);
1762 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1763 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1765 // we do this once manually, but it should be done automatically
1766 // when the engine goes out of scope (since it should gc in dtor)
1767 QMetaObject::invokeMethod(object, "performGc");
1770 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1776 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1777 QCOMPARE(dtorCount, expectedDtorCount);
1781 void tst_qdeclarativeecmascript::regExpBug()
1783 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1784 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1785 QVERIFY(object != 0);
1786 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1790 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1792 QString functionSource = QLatin1String("(function(object) { return ") +
1793 QLatin1String(source) + QLatin1String(" })");
1795 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1798 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1799 if (function.IsEmpty())
1801 v8::Handle<v8::Value> args[] = { o };
1802 function->Call(engine->global(), 1, args);
1803 return tc.HasCaught();
1806 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1807 const char *source, v8::Handle<v8::Value> result)
1809 QString functionSource = QLatin1String("(function(object) { return ") +
1810 QLatin1String(source) + QLatin1String(" })");
1812 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1815 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1816 if (function.IsEmpty())
1818 v8::Handle<v8::Value> args[] = { o };
1820 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1825 return value->StrictEquals(result);
1828 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1831 QString functionSource = QLatin1String("(function(object) { return ") +
1832 QLatin1String(source) + QLatin1String(" })");
1834 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1836 return v8::Handle<v8::Value>();
1837 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1838 if (function.IsEmpty())
1839 return v8::Handle<v8::Value>();
1840 v8::Handle<v8::Value> args[] = { o };
1842 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1845 return v8::Handle<v8::Value>();
1849 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1850 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1851 #define EVALUATE(source) evaluate(engine, object, source)
1853 void tst_qdeclarativeecmascript::callQtInvokables()
1855 MyInvokableObject o;
1857 QDeclarativeEngine qmlengine;
1858 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1860 QV8Engine *engine = ep->v8engine();
1862 v8::HandleScope handle_scope;
1863 v8::Context::Scope scope(engine->context());
1865 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1867 // Non-existent methods
1869 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1870 QCOMPARE(o.error(), false);
1871 QCOMPARE(o.invoked(), -1);
1872 QCOMPARE(o.actuals().count(), 0);
1875 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1876 QCOMPARE(o.error(), false);
1877 QCOMPARE(o.invoked(), -1);
1878 QCOMPARE(o.actuals().count(), 0);
1880 // Insufficient arguments
1882 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1883 QCOMPARE(o.error(), false);
1884 QCOMPARE(o.invoked(), -1);
1885 QCOMPARE(o.actuals().count(), 0);
1888 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1889 QCOMPARE(o.error(), false);
1890 QCOMPARE(o.invoked(), -1);
1891 QCOMPARE(o.actuals().count(), 0);
1893 // Excessive arguments
1895 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1896 QCOMPARE(o.error(), false);
1897 QCOMPARE(o.invoked(), 8);
1898 QCOMPARE(o.actuals().count(), 1);
1899 QCOMPARE(o.actuals().at(0), QVariant(10));
1902 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1903 QCOMPARE(o.error(), false);
1904 QCOMPARE(o.invoked(), 9);
1905 QCOMPARE(o.actuals().count(), 2);
1906 QCOMPARE(o.actuals().at(0), QVariant(10));
1907 QCOMPARE(o.actuals().at(1), QVariant(11));
1909 // Test return types
1911 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1912 QCOMPARE(o.error(), false);
1913 QCOMPARE(o.invoked(), 0);
1914 QCOMPARE(o.actuals().count(), 0);
1917 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1918 QCOMPARE(o.error(), false);
1919 QCOMPARE(o.invoked(), 1);
1920 QCOMPARE(o.actuals().count(), 0);
1923 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1924 QCOMPARE(o.error(), false);
1925 QCOMPARE(o.invoked(), 2);
1926 QCOMPARE(o.actuals().count(), 0);
1930 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1931 QVERIFY(!ret.IsEmpty());
1932 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1933 QCOMPARE(o.error(), false);
1934 QCOMPARE(o.invoked(), 3);
1935 QCOMPARE(o.actuals().count(), 0);
1940 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1941 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1942 QCOMPARE(o.error(), false);
1943 QCOMPARE(o.invoked(), 4);
1944 QCOMPARE(o.actuals().count(), 0);
1948 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1949 QCOMPARE(o.error(), false);
1950 QCOMPARE(o.invoked(), 5);
1951 QCOMPARE(o.actuals().count(), 0);
1955 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1956 QVERIFY(ret->IsString());
1957 QCOMPARE(engine->toString(ret), QString("Hello world"));
1958 QCOMPARE(o.error(), false);
1959 QCOMPARE(o.invoked(), 6);
1960 QCOMPARE(o.actuals().count(), 0);
1964 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1965 QCOMPARE(o.error(), false);
1966 QCOMPARE(o.invoked(), 7);
1967 QCOMPARE(o.actuals().count(), 0);
1971 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1972 QCOMPARE(o.error(), false);
1973 QCOMPARE(o.invoked(), 8);
1974 QCOMPARE(o.actuals().count(), 1);
1975 QCOMPARE(o.actuals().at(0), QVariant(94));
1978 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1979 QCOMPARE(o.error(), false);
1980 QCOMPARE(o.invoked(), 8);
1981 QCOMPARE(o.actuals().count(), 1);
1982 QCOMPARE(o.actuals().at(0), QVariant(94));
1985 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1986 QCOMPARE(o.error(), false);
1987 QCOMPARE(o.invoked(), 8);
1988 QCOMPARE(o.actuals().count(), 1);
1989 QCOMPARE(o.actuals().at(0), QVariant(0));
1992 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1993 QCOMPARE(o.error(), false);
1994 QCOMPARE(o.invoked(), 8);
1995 QCOMPARE(o.actuals().count(), 1);
1996 QCOMPARE(o.actuals().at(0), QVariant(0));
1999 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
2000 QCOMPARE(o.error(), false);
2001 QCOMPARE(o.invoked(), 8);
2002 QCOMPARE(o.actuals().count(), 1);
2003 QCOMPARE(o.actuals().at(0), QVariant(0));
2006 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2007 QCOMPARE(o.error(), false);
2008 QCOMPARE(o.invoked(), 8);
2009 QCOMPARE(o.actuals().count(), 1);
2010 QCOMPARE(o.actuals().at(0), QVariant(0));
2013 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2014 QCOMPARE(o.error(), false);
2015 QCOMPARE(o.invoked(), 9);
2016 QCOMPARE(o.actuals().count(), 2);
2017 QCOMPARE(o.actuals().at(0), QVariant(122));
2018 QCOMPARE(o.actuals().at(1), QVariant(9));
2021 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2022 QCOMPARE(o.error(), false);
2023 QCOMPARE(o.invoked(), 10);
2024 QCOMPARE(o.actuals().count(), 1);
2025 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2028 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2029 QCOMPARE(o.error(), false);
2030 QCOMPARE(o.invoked(), 10);
2031 QCOMPARE(o.actuals().count(), 1);
2032 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2035 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2036 QCOMPARE(o.error(), false);
2037 QCOMPARE(o.invoked(), 10);
2038 QCOMPARE(o.actuals().count(), 1);
2039 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2042 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2043 QCOMPARE(o.error(), false);
2044 QCOMPARE(o.invoked(), 10);
2045 QCOMPARE(o.actuals().count(), 1);
2046 QCOMPARE(o.actuals().at(0), QVariant(0));
2049 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2050 QCOMPARE(o.error(), false);
2051 QCOMPARE(o.invoked(), 10);
2052 QCOMPARE(o.actuals().count(), 1);
2053 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2056 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2057 QCOMPARE(o.error(), false);
2058 QCOMPARE(o.invoked(), 10);
2059 QCOMPARE(o.actuals().count(), 1);
2060 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2063 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2064 QCOMPARE(o.error(), false);
2065 QCOMPARE(o.invoked(), 11);
2066 QCOMPARE(o.actuals().count(), 1);
2067 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2070 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2071 QCOMPARE(o.error(), false);
2072 QCOMPARE(o.invoked(), 11);
2073 QCOMPARE(o.actuals().count(), 1);
2074 QCOMPARE(o.actuals().at(0), QVariant("19"));
2078 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2079 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2080 QCOMPARE(o.error(), false);
2081 QCOMPARE(o.invoked(), 11);
2082 QCOMPARE(o.actuals().count(), 1);
2083 QCOMPARE(o.actuals().at(0), QVariant(expected));
2087 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2088 QCOMPARE(o.error(), false);
2089 QCOMPARE(o.invoked(), 11);
2090 QCOMPARE(o.actuals().count(), 1);
2091 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2094 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2095 QCOMPARE(o.error(), false);
2096 QCOMPARE(o.invoked(), 11);
2097 QCOMPARE(o.actuals().count(), 1);
2098 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2101 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2102 QCOMPARE(o.error(), false);
2103 QCOMPARE(o.invoked(), 12);
2104 QCOMPARE(o.actuals().count(), 1);
2105 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2108 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2109 QCOMPARE(o.error(), false);
2110 QCOMPARE(o.invoked(), 12);
2111 QCOMPARE(o.actuals().count(), 1);
2112 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2115 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2116 QCOMPARE(o.error(), false);
2117 QCOMPARE(o.invoked(), 12);
2118 QCOMPARE(o.actuals().count(), 1);
2119 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2122 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2123 QCOMPARE(o.error(), false);
2124 QCOMPARE(o.invoked(), 12);
2125 QCOMPARE(o.actuals().count(), 1);
2126 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2129 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2130 QCOMPARE(o.error(), false);
2131 QCOMPARE(o.invoked(), 12);
2132 QCOMPARE(o.actuals().count(), 1);
2133 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2136 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2137 QCOMPARE(o.error(), false);
2138 QCOMPARE(o.invoked(), 12);
2139 QCOMPARE(o.actuals().count(), 1);
2140 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2143 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2144 QCOMPARE(o.error(), false);
2145 QCOMPARE(o.invoked(), 13);
2146 QCOMPARE(o.actuals().count(), 1);
2147 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2150 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2151 QCOMPARE(o.error(), false);
2152 QCOMPARE(o.invoked(), 13);
2153 QCOMPARE(o.actuals().count(), 1);
2154 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2157 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2158 QCOMPARE(o.error(), false);
2159 QCOMPARE(o.invoked(), 13);
2160 QCOMPARE(o.actuals().count(), 1);
2161 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2164 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2165 QCOMPARE(o.error(), false);
2166 QCOMPARE(o.invoked(), 13);
2167 QCOMPARE(o.actuals().count(), 1);
2168 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2171 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2172 QCOMPARE(o.error(), false);
2173 QCOMPARE(o.invoked(), 13);
2174 QCOMPARE(o.actuals().count(), 1);
2175 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2178 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2179 QCOMPARE(o.error(), false);
2180 QCOMPARE(o.invoked(), 14);
2181 QCOMPARE(o.actuals().count(), 1);
2182 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2185 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2186 QCOMPARE(o.error(), false);
2187 QCOMPARE(o.invoked(), 14);
2188 QCOMPARE(o.actuals().count(), 1);
2189 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2192 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2193 QCOMPARE(o.error(), false);
2194 QCOMPARE(o.invoked(), 14);
2195 QCOMPARE(o.actuals().count(), 1);
2196 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2199 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2200 QCOMPARE(o.error(), false);
2201 QCOMPARE(o.invoked(), 14);
2202 QCOMPARE(o.actuals().count(), 1);
2203 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2206 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2207 QCOMPARE(o.error(), false);
2208 QCOMPARE(o.invoked(), 15);
2209 QCOMPARE(o.actuals().count(), 2);
2210 QCOMPARE(o.actuals().at(0), QVariant(4));
2211 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2214 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2215 QCOMPARE(o.error(), false);
2216 QCOMPARE(o.invoked(), 15);
2217 QCOMPARE(o.actuals().count(), 2);
2218 QCOMPARE(o.actuals().at(0), QVariant(8));
2219 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2222 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2223 QCOMPARE(o.error(), false);
2224 QCOMPARE(o.invoked(), 15);
2225 QCOMPARE(o.actuals().count(), 2);
2226 QCOMPARE(o.actuals().at(0), QVariant(3));
2227 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2230 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2231 QCOMPARE(o.error(), false);
2232 QCOMPARE(o.invoked(), 15);
2233 QCOMPARE(o.actuals().count(), 2);
2234 QCOMPARE(o.actuals().at(0), QVariant(44));
2235 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2238 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2239 QCOMPARE(o.error(), false);
2240 QCOMPARE(o.invoked(), -1);
2241 QCOMPARE(o.actuals().count(), 0);
2244 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2245 QCOMPARE(o.error(), false);
2246 QCOMPARE(o.invoked(), 16);
2247 QCOMPARE(o.actuals().count(), 1);
2248 QCOMPARE(o.actuals().at(0), QVariant(10));
2251 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2252 QCOMPARE(o.error(), false);
2253 QCOMPARE(o.invoked(), 17);
2254 QCOMPARE(o.actuals().count(), 2);
2255 QCOMPARE(o.actuals().at(0), QVariant(10));
2256 QCOMPARE(o.actuals().at(1), QVariant(11));
2259 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2260 QCOMPARE(o.error(), false);
2261 QCOMPARE(o.invoked(), 18);
2262 QCOMPARE(o.actuals().count(), 1);
2263 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2266 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2267 QCOMPARE(o.error(), false);
2268 QCOMPARE(o.invoked(), 19);
2269 QCOMPARE(o.actuals().count(), 1);
2270 QCOMPARE(o.actuals().at(0), QVariant(9));
2273 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2274 QCOMPARE(o.error(), false);
2275 QCOMPARE(o.invoked(), 20);
2276 QCOMPARE(o.actuals().count(), 2);
2277 QCOMPARE(o.actuals().at(0), QVariant(10));
2278 QCOMPARE(o.actuals().at(1), QVariant(19));
2281 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2282 QCOMPARE(o.error(), false);
2283 QCOMPARE(o.invoked(), 20);
2284 QCOMPARE(o.actuals().count(), 2);
2285 QCOMPARE(o.actuals().at(0), QVariant(10));
2286 QCOMPARE(o.actuals().at(1), QVariant(13));
2289 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2290 QCOMPARE(o.error(), false);
2291 QCOMPARE(o.invoked(), -3);
2292 QCOMPARE(o.actuals().count(), 1);
2293 QCOMPARE(o.actuals().at(0), QVariant(9));
2296 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2297 QCOMPARE(o.error(), false);
2298 QCOMPARE(o.invoked(), 21);
2299 QCOMPARE(o.actuals().count(), 2);
2300 QCOMPARE(o.actuals().at(0), QVariant(9));
2301 QCOMPARE(o.actuals().at(1), QVariant());
2304 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2305 QCOMPARE(o.error(), false);
2306 QCOMPARE(o.invoked(), 21);
2307 QCOMPARE(o.actuals().count(), 2);
2308 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2309 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2312 // QTBUG-13047 (check that you can pass registered object types as args)
2313 void tst_qdeclarativeecmascript::invokableObjectArg()
2315 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2317 QObject *o = component.create();
2319 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2321 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2326 // QTBUG-13047 (check that you can return registered object types from methods)
2327 void tst_qdeclarativeecmascript::invokableObjectRet()
2329 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2331 QObject *o = component.create();
2333 QCOMPARE(o->property("test").toBool(), true);
2338 void tst_qdeclarativeecmascript::listToVariant()
2340 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2342 MyQmlContainer container;
2344 QDeclarativeContext context(engine.rootContext());
2345 context.setContextObject(&container);
2347 QObject *object = component.create(&context);
2348 QVERIFY(object != 0);
2350 QVariant v = object->property("test");
2351 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2352 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2358 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2359 void tst_qdeclarativeecmascript::listAssignment()
2361 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2362 QObject *obj = component.create();
2363 QCOMPARE(obj->property("list1length").toInt(), 2);
2364 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2365 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2366 QCOMPARE(list1.count(&list1), list2.count(&list2));
2367 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2368 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2373 void tst_qdeclarativeecmascript::multiEngineObject()
2376 obj.setStringProperty("Howdy planet");
2378 QDeclarativeEngine e1;
2379 e1.rootContext()->setContextProperty("thing", &obj);
2380 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2382 QDeclarativeEngine e2;
2383 e2.rootContext()->setContextProperty("thing", &obj);
2384 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2386 QObject *o1 = c1.create();
2387 QObject *o2 = c2.create();
2389 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2390 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2396 // Test that references to QObjects are cleanup when the object is destroyed
2397 void tst_qdeclarativeecmascript::deletedObject()
2399 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2401 QObject *object = component.create();
2403 QCOMPARE(object->property("test1").toBool(), true);
2404 QCOMPARE(object->property("test2").toBool(), true);
2405 QCOMPARE(object->property("test3").toBool(), true);
2406 QCOMPARE(object->property("test4").toBool(), true);
2411 void tst_qdeclarativeecmascript::attachedPropertyScope()
2413 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2415 QObject *object = component.create();
2416 QVERIFY(object != 0);
2418 MyQmlAttachedObject *attached =
2419 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2420 QVERIFY(attached != 0);
2422 QCOMPARE(object->property("value2").toInt(), 0);
2424 attached->emitMySignal();
2426 QCOMPARE(object->property("value2").toInt(), 9);
2431 void tst_qdeclarativeecmascript::scriptConnect()
2434 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2436 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2437 QVERIFY(object != 0);
2439 QCOMPARE(object->property("test").toBool(), false);
2440 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2441 QCOMPARE(object->property("test").toBool(), true);
2447 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2449 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2450 QVERIFY(object != 0);
2452 QCOMPARE(object->property("test").toBool(), false);
2453 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2454 QCOMPARE(object->property("test").toBool(), true);
2460 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2462 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2463 QVERIFY(object != 0);
2465 QCOMPARE(object->property("test").toBool(), false);
2466 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2467 QCOMPARE(object->property("test").toBool(), true);
2473 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2475 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2476 QVERIFY(object != 0);
2478 QCOMPARE(object->methodCalled(), false);
2479 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2480 QCOMPARE(object->methodCalled(), true);
2486 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2488 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2489 QVERIFY(object != 0);
2491 QCOMPARE(object->methodCalled(), false);
2492 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2493 QCOMPARE(object->methodCalled(), true);
2499 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2501 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2502 QVERIFY(object != 0);
2504 QCOMPARE(object->property("test").toInt(), 0);
2505 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2506 QCOMPARE(object->property("test").toInt(), 2);
2512 void tst_qdeclarativeecmascript::scriptDisconnect()
2515 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2517 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2518 QVERIFY(object != 0);
2520 QCOMPARE(object->property("test").toInt(), 0);
2521 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2522 QCOMPARE(object->property("test").toInt(), 1);
2523 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2524 QCOMPARE(object->property("test").toInt(), 2);
2525 emit object->basicSignal();
2526 QCOMPARE(object->property("test").toInt(), 2);
2527 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2528 QCOMPARE(object->property("test").toInt(), 2);
2534 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2536 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2537 QVERIFY(object != 0);
2539 QCOMPARE(object->property("test").toInt(), 0);
2540 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2541 QCOMPARE(object->property("test").toInt(), 1);
2542 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2543 QCOMPARE(object->property("test").toInt(), 2);
2544 emit object->basicSignal();
2545 QCOMPARE(object->property("test").toInt(), 2);
2546 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2547 QCOMPARE(object->property("test").toInt(), 2);
2553 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2555 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2556 QVERIFY(object != 0);
2558 QCOMPARE(object->property("test").toInt(), 0);
2559 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2560 QCOMPARE(object->property("test").toInt(), 1);
2561 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2562 QCOMPARE(object->property("test").toInt(), 2);
2563 emit object->basicSignal();
2564 QCOMPARE(object->property("test").toInt(), 2);
2565 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2566 QCOMPARE(object->property("test").toInt(), 3);
2571 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2573 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2574 QVERIFY(object != 0);
2576 QCOMPARE(object->property("test").toInt(), 0);
2577 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2578 QCOMPARE(object->property("test").toInt(), 1);
2579 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2580 QCOMPARE(object->property("test").toInt(), 2);
2581 emit object->basicSignal();
2582 QCOMPARE(object->property("test").toInt(), 2);
2583 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2584 QCOMPARE(object->property("test").toInt(), 3);
2590 class OwnershipObject : public QObject
2594 OwnershipObject() { object = new QObject; }
2596 QPointer<QObject> object;
2599 QObject *getObject() { return object; }
2602 void tst_qdeclarativeecmascript::ownership()
2604 OwnershipObject own;
2605 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2606 context->setContextObject(&own);
2609 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2611 QVERIFY(own.object != 0);
2613 QObject *object = component.create(context);
2615 engine.collectGarbage();
2617 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2619 QVERIFY(own.object == 0);
2624 own.object = new QObject(&own);
2627 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2629 QVERIFY(own.object != 0);
2631 QObject *object = component.create(context);
2633 engine.collectGarbage();
2635 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2637 QVERIFY(own.object != 0);
2645 class CppOwnershipReturnValue : public QObject
2649 CppOwnershipReturnValue() : value(0) {}
2650 ~CppOwnershipReturnValue() { delete value; }
2652 Q_INVOKABLE QObject *create() {
2653 value = new QObject;
2654 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2658 Q_INVOKABLE MyQmlObject *createQmlObject() {
2659 MyQmlObject *rv = new MyQmlObject;
2664 QPointer<QObject> value;
2668 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2669 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2671 CppOwnershipReturnValue source;
2674 QDeclarativeEngine engine;
2675 engine.rootContext()->setContextProperty("source", &source);
2677 QVERIFY(source.value == 0);
2679 QDeclarativeComponent component(&engine);
2680 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2682 QObject *object = component.create();
2684 QVERIFY(object != 0);
2685 QVERIFY(source.value != 0);
2690 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2692 QVERIFY(source.value != 0);
2696 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2698 CppOwnershipReturnValue source;
2701 QDeclarativeEngine engine;
2702 engine.rootContext()->setContextProperty("source", &source);
2704 QVERIFY(source.value == 0);
2706 QDeclarativeComponent component(&engine);
2707 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2709 QObject *object = component.create();
2711 QVERIFY(object != 0);
2712 QVERIFY(source.value != 0);
2717 engine.collectGarbage();
2718 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2720 QVERIFY(source.value == 0);
2723 class QListQObjectMethodsObject : public QObject
2727 QListQObjectMethodsObject() {
2728 m_objects.append(new MyQmlObject());
2729 m_objects.append(new MyQmlObject());
2732 ~QListQObjectMethodsObject() {
2733 qDeleteAll(m_objects);
2737 QList<QObject *> getObjects() { return m_objects; }
2740 QList<QObject *> m_objects;
2743 // Tests that returning a QList<QObject*> from a method works
2744 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2746 QListQObjectMethodsObject obj;
2747 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2748 context->setContextObject(&obj);
2750 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2752 QObject *object = component.create(context);
2754 QCOMPARE(object->property("test").toInt(), 2);
2755 QCOMPARE(object->property("test2").toBool(), true);
2762 void tst_qdeclarativeecmascript::strictlyEquals()
2764 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2766 QObject *object = component.create();
2767 QVERIFY(object != 0);
2769 QCOMPARE(object->property("test1").toBool(), true);
2770 QCOMPARE(object->property("test2").toBool(), true);
2771 QCOMPARE(object->property("test3").toBool(), true);
2772 QCOMPARE(object->property("test4").toBool(), true);
2773 QCOMPARE(object->property("test5").toBool(), true);
2774 QCOMPARE(object->property("test6").toBool(), true);
2775 QCOMPARE(object->property("test7").toBool(), true);
2776 QCOMPARE(object->property("test8").toBool(), true);
2781 void tst_qdeclarativeecmascript::compiled()
2783 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2785 QObject *object = component.create();
2786 QVERIFY(object != 0);
2788 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2789 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2790 QCOMPARE(object->property("test3").toBool(), true);
2791 QCOMPARE(object->property("test4").toBool(), false);
2792 QCOMPARE(object->property("test5").toBool(), false);
2793 QCOMPARE(object->property("test6").toBool(), true);
2795 QCOMPARE(object->property("test7").toInt(), 185);
2796 QCOMPARE(object->property("test8").toInt(), 167);
2797 QCOMPARE(object->property("test9").toBool(), true);
2798 QCOMPARE(object->property("test10").toBool(), false);
2799 QCOMPARE(object->property("test11").toBool(), false);
2800 QCOMPARE(object->property("test12").toBool(), true);
2802 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2803 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2804 QCOMPARE(object->property("test15").toBool(), false);
2805 QCOMPARE(object->property("test16").toBool(), true);
2807 QCOMPARE(object->property("test17").toInt(), 5);
2808 QCOMPARE(object->property("test18").toReal(), qreal(176));
2809 QCOMPARE(object->property("test19").toInt(), 7);
2810 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2811 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2812 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2813 QCOMPARE(object->property("test23").toBool(), true);
2814 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2815 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2820 // Test that numbers assigned in bindings as strings work consistently
2821 void tst_qdeclarativeecmascript::numberAssignment()
2823 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2825 QObject *object = component.create();
2826 QVERIFY(object != 0);
2828 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2829 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2830 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2831 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2832 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2834 QCOMPARE(object->property("test5"), QVariant((int)7));
2835 QCOMPARE(object->property("test6"), QVariant((int)7));
2836 QCOMPARE(object->property("test7"), QVariant((int)6));
2837 QCOMPARE(object->property("test8"), QVariant((int)6));
2839 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2840 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2841 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2842 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2847 void tst_qdeclarativeecmascript::propertySplicing()
2849 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2851 QObject *object = component.create();
2852 QVERIFY(object != 0);
2854 QCOMPARE(object->property("test").toBool(), true);
2860 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2862 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2864 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2865 QVERIFY(object != 0);
2867 MyQmlObject::MyType type;
2868 type.value = 0x8971123;
2869 emit object->signalWithUnknownType(type);
2871 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2873 QCOMPARE(result.value, type.value);
2879 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2881 QTest::addColumn<QString>("expression");
2882 QTest::addColumn<QString>("compare");
2884 QString compareStrict("(function(a, b) { return a === b; })");
2885 QTest::newRow("true") << "true" << compareStrict;
2886 QTest::newRow("undefined") << "undefined" << compareStrict;
2887 QTest::newRow("null") << "null" << compareStrict;
2888 QTest::newRow("123") << "123" << compareStrict;
2889 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2891 QString comparePropertiesStrict(
2893 " if (typeof b != 'object')"
2895 " var props = Object.getOwnPropertyNames(b);"
2896 " for (var i = 0; i < props.length; ++i) {"
2897 " var p = props[i];"
2898 " return arguments.callee(a[p], b[p]);"
2901 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2902 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2905 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2907 QFETCH(QString, expression);
2908 QFETCH(QString, compare);
2910 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2911 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2912 QVERIFY(object != 0);
2914 QJSValue value = engine.evaluate(expression);
2915 QVERIFY(!engine.hasUncaughtException());
2916 object->setProperty("expression", expression);
2917 object->setProperty("compare", compare);
2918 object->setProperty("pass", false);
2920 emit object->signalWithVariant(QVariant::fromValue(value));
2921 QVERIFY(object->property("pass").toBool());
2924 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2926 signalWithJSValueInVariant_data();
2929 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2931 QFETCH(QString, expression);
2932 QFETCH(QString, compare);
2934 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2935 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2936 QVERIFY(object != 0);
2939 QJSValue value = engine2.evaluate(expression);
2940 QVERIFY(!engine2.hasUncaughtException());
2941 object->setProperty("expression", expression);
2942 object->setProperty("compare", compare);
2943 object->setProperty("pass", false);
2945 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2946 emit object->signalWithVariant(QVariant::fromValue(value));
2947 QVERIFY(!object->property("pass").toBool());
2950 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2952 signalWithJSValueInVariant_data();
2955 void tst_qdeclarativeecmascript::signalWithQJSValue()
2957 QFETCH(QString, expression);
2958 QFETCH(QString, compare);
2960 QDeclarativeComponent component(&engine, TEST_FILE("signalWithQJSValue.qml"));
2961 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2962 QVERIFY(object != 0);
2964 QJSValue value = engine.evaluate(expression);
2965 QVERIFY(!engine.hasUncaughtException());
2966 object->setProperty("expression", expression);
2967 object->setProperty("compare", compare);
2968 object->setProperty("pass", false);
2970 emit object->signalWithQJSValue(value);
2972 QVERIFY(object->property("pass").toBool());
2973 QVERIFY(object->qjsvalue().strictlyEquals(value));
2976 void tst_qdeclarativeecmascript::moduleApi_data()
2978 QTest::addColumn<QUrl>("testfile");
2979 QTest::addColumn<QString>("errorMessage");
2980 QTest::addColumn<QStringList>("warningMessages");
2981 QTest::addColumn<QStringList>("readProperties");
2982 QTest::addColumn<QVariantList>("readExpectedValues");
2983 QTest::addColumn<QStringList>("writeProperties");
2984 QTest::addColumn<QVariantList>("writeValues");
2985 QTest::addColumn<QStringList>("readBackProperties");
2986 QTest::addColumn<QVariantList>("readBackExpectedValues");
2988 QTest::newRow("qobject, register + read + method")
2989 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2992 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2993 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2994 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
3000 QTest::newRow("script, register + read")
3001 << TEST_FILE("moduleapi/scriptModuleApi.qml")
3004 << (QStringList() << "scriptTest")
3005 << (QVariantList() << 13)
3011 QTest::newRow("qobject, caching + read")
3012 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
3015 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3016 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3022 QTest::newRow("script, caching + read")
3023 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
3026 << (QStringList() << "scriptTest")
3027 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3033 QTest::newRow("qobject, writing + readonly constraints")
3034 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
3036 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3037 << (QStringList() << "readOnlyProperty" << "writableProperty")
3038 << (QVariantList() << 20 << 50)
3039 << (QStringList() << "firstProperty" << "writableProperty")
3040 << (QVariantList() << 30 << 30)
3041 << (QStringList() << "readOnlyProperty" << "writableProperty")
3042 << (QVariantList() << 20 << 30);
3044 QTest::newRow("script, writing + readonly constraints")
3045 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
3047 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3048 << (QStringList() << "readBack" << "unchanged")
3049 << (QVariantList() << 13 << 42)
3050 << (QStringList() << "firstProperty" << "secondProperty")
3051 << (QVariantList() << 30 << 30)
3052 << (QStringList() << "readBack" << "unchanged")
3053 << (QVariantList() << 30 << 42);
3055 QTest::newRow("qobject module API enum values in JS")
3056 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3059 << (QStringList() << "enumValue" << "enumMethod")
3060 << (QVariantList() << 42 << 30)
3066 QTest::newRow("qobject, invalid major version fail")
3067 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3068 << QString("QDeclarativeComponent: Component is not ready")
3077 QTest::newRow("qobject, invalid minor version fail")
3078 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3079 << QString("QDeclarativeComponent: Component is not ready")
3089 void tst_qdeclarativeecmascript::moduleApi()
3091 QFETCH(QUrl, testfile);
3092 QFETCH(QString, errorMessage);
3093 QFETCH(QStringList, warningMessages);
3094 QFETCH(QStringList, readProperties);
3095 QFETCH(QVariantList, readExpectedValues);
3096 QFETCH(QStringList, writeProperties);
3097 QFETCH(QVariantList, writeValues);
3098 QFETCH(QStringList, readBackProperties);
3099 QFETCH(QVariantList, readBackExpectedValues);
3101 QDeclarativeComponent component(&engine, testfile);
3103 if (!errorMessage.isEmpty())
3104 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3106 if (warningMessages.size())
3107 foreach (const QString &warning, warningMessages)
3108 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3110 QObject *object = component.create();
3111 if (!errorMessage.isEmpty()) {
3112 QVERIFY(object == 0);
3114 QVERIFY(object != 0);
3115 for (int i = 0; i < readProperties.size(); ++i)
3116 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3117 for (int i = 0; i < writeProperties.size(); ++i)
3118 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3119 for (int i = 0; i < readBackProperties.size(); ++i)
3120 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3125 void tst_qdeclarativeecmascript::importScripts_data()
3127 QTest::addColumn<QUrl>("testfile");
3128 QTest::addColumn<QString>("errorMessage");
3129 QTest::addColumn<QStringList>("warningMessages");
3130 QTest::addColumn<QStringList>("propertyNames");
3131 QTest::addColumn<QVariantList>("propertyValues");
3133 QTest::newRow("basic functionality")
3134 << TEST_FILE("jsimport/testImport.qml")
3137 << (QStringList() << QLatin1String("importedScriptStringValue")
3138 << QLatin1String("importedScriptFunctionValue")
3139 << QLatin1String("importedModuleAttachedPropertyValue")
3140 << QLatin1String("importedModuleEnumValue"))
3141 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3146 QTest::newRow("import scoping")
3147 << TEST_FILE("jsimport/testImportScoping.qml")
3150 << (QStringList() << QLatin1String("componentError"))
3151 << (QVariantList() << QVariant(5));
3153 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3154 << TEST_FILE("jsimportfail/failOne.qml")
3156 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3157 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3158 << (QVariantList() << QVariant(QString()));
3160 QTest::newRow("javascript imports in an import should be private to the import scope")
3161 << TEST_FILE("jsimportfail/failTwo.qml")
3163 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3164 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3165 << (QVariantList() << QVariant(QString()));
3167 QTest::newRow("module imports in an import should be private to the import scope")
3168 << TEST_FILE("jsimportfail/failThree.qml")
3170 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3171 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3172 << (QVariantList() << QVariant(false));
3174 QTest::newRow("typenames in an import should be private to the import scope")
3175 << TEST_FILE("jsimportfail/failFour.qml")
3177 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3178 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3179 << (QVariantList() << QVariant(0));
3181 QTest::newRow("import with imports has it's own activation scope")
3182 << TEST_FILE("jsimportfail/failFive.qml")
3184 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3185 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3186 << (QStringList() << QLatin1String("componentError"))
3187 << (QVariantList() << QVariant(0));
3189 QTest::newRow("import pragma library script")
3190 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3193 << (QStringList() << QLatin1String("testValue"))
3194 << (QVariantList() << QVariant(31));
3196 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3197 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3200 << (QStringList() << QLatin1String("testValue"))
3201 << (QVariantList() << QVariant(0));
3203 QTest::newRow("import pragma library script which has an import")
3204 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3207 << (QStringList() << QLatin1String("testValue"))
3208 << (QVariantList() << QVariant(55));
3210 QTest::newRow("import pragma library script which has a pragma library import")
3211 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3214 << (QStringList() << QLatin1String("testValue"))
3215 << (QVariantList() << QVariant(18));
3218 void tst_qdeclarativeecmascript::importScripts()
3220 QFETCH(QUrl, testfile);
3221 QFETCH(QString, errorMessage);
3222 QFETCH(QStringList, warningMessages);
3223 QFETCH(QStringList, propertyNames);
3224 QFETCH(QVariantList, propertyValues);
3226 QDeclarativeComponent component(&engine, testfile);
3228 if (!errorMessage.isEmpty())
3229 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3231 if (warningMessages.size())
3232 foreach (const QString &warning, warningMessages)
3233 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3235 QObject *object = component.create();
3236 if (!errorMessage.isEmpty()) {
3237 QVERIFY(object == 0);
3239 QVERIFY(object != 0);
3240 for (int i = 0; i < propertyNames.size(); ++i)
3241 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3246 void tst_qdeclarativeecmascript::scarceResources_other()
3248 /* These tests require knowledge of state, since we test values after
3249 performing signal or function invocation. */
3251 QPixmap origPixmap(100, 100);
3252 origPixmap.fill(Qt::blue);
3253 QString srp_name, expectedWarning;
3254 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3255 ScarceResourceObject *eo = 0;
3257 QObject *object = 0;
3259 /* property var semantics */
3261 // test that scarce resources are handled properly in signal invocation
3262 QDeclarativeComponent varComponentTen(&engine, TEST_FILE("scarceResourceSignal.var.qml"));
3263 object = varComponentTen.create();
3264 srsc = object->findChild<QObject*>("srsc");
3266 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3267 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3268 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3269 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3270 QMetaObject::invokeMethod(srsc, "testSignal");
3271 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3272 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3273 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3274 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3275 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3276 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3277 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3278 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3279 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3280 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3283 // test that scarce resources are handled properly from js functions in qml files
3284 QDeclarativeComponent varComponentEleven(&engine, TEST_FILE("scarceResourceFunction.var.qml"));
3285 object = varComponentEleven.create();
3286 QVERIFY(object != 0);
3287 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3288 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3289 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3290 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3291 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3292 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3293 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3294 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3295 QMetaObject::invokeMethod(object, "releaseScarceResource");
3296 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3297 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3298 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3299 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3302 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3303 QDeclarativeComponent varComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
3304 object = varComponentTwelve.create();
3305 QVERIFY(object != 0);
3306 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3307 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3308 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3309 srp_name = object->property("srp_name").toString();
3310 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3311 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3312 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3313 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3314 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3315 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3316 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3319 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3320 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3321 QDeclarativeComponent varComponentThirteen(&engine, TEST_FILE("scarceResourceObjectGc.var.qml"));
3322 object = varComponentThirteen.create();
3323 QVERIFY(object != 0);
3324 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3325 QMetaObject::invokeMethod(object, "assignVarProperty");
3326 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3327 QMetaObject::invokeMethod(object, "deassignVarProperty");
3328 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3331 /* property variant semantics */
3333 // test that scarce resources are handled properly in signal invocation
3334 QDeclarativeComponent variantComponentTen(&engine, TEST_FILE("scarceResourceSignal.variant.qml"));
3335 object = variantComponentTen.create();
3336 QVERIFY(object != 0);
3337 srsc = object->findChild<QObject*>("srsc");
3339 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3340 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3341 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3342 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3343 QMetaObject::invokeMethod(srsc, "testSignal");
3344 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3345 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3346 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3347 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3348 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3349 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3350 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3351 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3352 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3353 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3356 // test that scarce resources are handled properly from js functions in qml files
3357 QDeclarativeComponent variantComponentEleven(&engine, TEST_FILE("scarceResourceFunction.variant.qml"));
3358 object = variantComponentEleven.create();
3359 QVERIFY(object != 0);
3360 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3361 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3362 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3363 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3364 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3365 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3366 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3367 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3368 QMetaObject::invokeMethod(object, "releaseScarceResource");
3369 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3370 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3371 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3372 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3375 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3376 QDeclarativeComponent variantComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.variant.qml"));
3377 object = variantComponentTwelve.create();
3378 QVERIFY(object != 0);
3379 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3380 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3381 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3382 srp_name = object->property("srp_name").toString();
3383 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3384 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3385 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3386 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3387 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3388 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3389 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3393 void tst_qdeclarativeecmascript::scarceResources_data()
3395 QTest::addColumn<QUrl>("qmlFile");
3396 QTest::addColumn<bool>("readDetachStatus");
3397 QTest::addColumn<bool>("expectedDetachStatus");
3398 QTest::addColumn<QStringList>("propertyNames");
3399 QTest::addColumn<QVariantList>("expectedValidity");
3400 QTest::addColumn<QVariantList>("expectedValues");
3401 QTest::addColumn<QStringList>("expectedErrors");
3403 QPixmap origPixmap(100, 100);
3404 origPixmap.fill(Qt::blue);
3406 /* property var semantics */
3408 // in the following three cases, the instance created from the component
3409 // has a property which is a copy of the scarce resource; hence, the
3410 // resource should NOT be detached prior to deletion of the object instance,
3411 // unless the resource is destroyed explicitly.
3412 QTest::newRow("var: import scarce resource copy directly")
3413 << TEST_FILE("scarceResourceCopy.var.qml")
3415 << false // won't be detached, because assigned to property and not explicitly released
3416 << (QStringList() << QLatin1String("scarceResourceCopy"))
3417 << (QList<QVariant>() << true)
3418 << (QList<QVariant>() << origPixmap)
3421 QTest::newRow("var: import scarce resource copy from JS")
3422 << TEST_FILE("scarceResourceCopyFromJs.var.qml")
3424 << false // won't be detached, because assigned to property and not explicitly released
3425 << (QStringList() << QLatin1String("scarceResourceCopy"))
3426 << (QList<QVariant>() << true)
3427 << (QList<QVariant>() << origPixmap)
3430 QTest::newRow("var: import released scarce resource copy from JS")
3431 << TEST_FILE("scarceResourceDestroyedCopy.var.qml")
3433 << true // explicitly released, so it will be detached
3434 << (QStringList() << QLatin1String("scarceResourceCopy"))
3435 << (QList<QVariant>() << false)
3436 << (QList<QVariant>() << QVariant())
3439 // in the following three cases, no other copy should exist in memory,
3440 // and so it should be detached (unless explicitly preserved).
3441 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3442 << TEST_FILE("scarceResourceTest.var.qml")
3444 << true // auto released, so it will be detached
3445 << (QStringList() << QLatin1String("scarceResourceTest"))
3446 << (QList<QVariant>() << true)
3447 << (QList<QVariant>() << QVariant(100))
3449 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3450 << TEST_FILE("scarceResourceTestPreserve.var.qml")
3452 << false // won't be detached because we explicitly preserve it
3453 << (QStringList() << QLatin1String("scarceResourceTest"))
3454 << (QList<QVariant>() << true)
3455 << (QList<QVariant>() << QVariant(100))
3457 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3458 << TEST_FILE("scarceResourceTestMultiple.var.qml")
3460 << true // will be detached because all resources were released manually or automatically.
3461 << (QStringList() << QLatin1String("scarceResourceTest"))
3462 << (QList<QVariant>() << true)
3463 << (QList<QVariant>() << QVariant(100))
3466 // In the following three cases, test that scarce resources are handled
3467 // correctly for imports.
3468 QTest::newRow("var: import with no binding")
3469 << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
3470 << false // cannot check detach status.
3473 << QList<QVariant>()
3474 << QList<QVariant>()
3476 QTest::newRow("var: import with binding without explicit preserve")
3477 << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
3480 << (QStringList() << QLatin1String("scarceResourceCopy"))
3481 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3482 << (QList<QVariant>() << QVariant())
3484 QTest::newRow("var: import with explicit release after binding evaluation")
3485 << TEST_FILE("scarceResourceCopyImport.var.qml")
3488 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3489 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3490 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3492 QTest::newRow("var: import with different js objects")
3493 << TEST_FILE("scarceResourceCopyImportDifferent.var.qml")
3496 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3497 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3498 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3500 QTest::newRow("var: import with different js objects and explicit release")
3501 << TEST_FILE("scarceResourceMultipleDifferentNoBinding.var.qml")
3504 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3505 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3506 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3508 QTest::newRow("var: import with same js objects and explicit release")
3509 << TEST_FILE("scarceResourceMultipleSameNoBinding.var.qml")
3512 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3513 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3514 << (QList<QVariant>() << QVariant() << QVariant())
3516 QTest::newRow("var: binding with same js objects and explicit release")
3517 << TEST_FILE("scarceResourceMultipleSameWithBinding.var.qml")
3520 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3521 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3522 << (QList<QVariant>() << QVariant() << QVariant())
3526 /* property variant semantics */
3528 // in the following three cases, the instance created from the component
3529 // has a property which is a copy of the scarce resource; hence, the
3530 // resource should NOT be detached prior to deletion of the object instance,
3531 // unless the resource is destroyed explicitly.
3532 QTest::newRow("variant: import scarce resource copy directly")
3533 << TEST_FILE("scarceResourceCopy.variant.qml")
3535 << false // won't be detached, because assigned to property and not explicitly released
3536 << (QStringList() << QLatin1String("scarceResourceCopy"))
3537 << (QList<QVariant>() << true)
3538 << (QList<QVariant>() << origPixmap)
3541 QTest::newRow("variant: import scarce resource copy from JS")
3542 << TEST_FILE("scarceResourceCopyFromJs.variant.qml")
3544 << false // won't be detached, because assigned to property and not explicitly released
3545 << (QStringList() << QLatin1String("scarceResourceCopy"))
3546 << (QList<QVariant>() << true)
3547 << (QList<QVariant>() << origPixmap)
3550 QTest::newRow("variant: import released scarce resource copy from JS")
3551 << TEST_FILE("scarceResourceDestroyedCopy.variant.qml")
3553 << true // explicitly released, so it will be detached
3554 << (QStringList() << QLatin1String("scarceResourceCopy"))
3555 << (QList<QVariant>() << false)
3556 << (QList<QVariant>() << QVariant())
3559 // in the following three cases, no other copy should exist in memory,
3560 // and so it should be detached (unless explicitly preserved).
3561 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3562 << TEST_FILE("scarceResourceTest.variant.qml")
3564 << true // auto released, so it will be detached
3565 << (QStringList() << QLatin1String("scarceResourceTest"))
3566 << (QList<QVariant>() << true)
3567 << (QList<QVariant>() << QVariant(100))
3569 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3570 << TEST_FILE("scarceResourceTestPreserve.variant.qml")
3572 << false // won't be detached because we explicitly preserve it
3573 << (QStringList() << QLatin1String("scarceResourceTest"))
3574 << (QList<QVariant>() << true)
3575 << (QList<QVariant>() << QVariant(100))
3577 QTest::newRow("variant: import multiple scarce resources")
3578 << TEST_FILE("scarceResourceTestMultiple.variant.qml")
3580 << true // will be detached because all resources were released manually or automatically.
3581 << (QStringList() << QLatin1String("scarceResourceTest"))
3582 << (QList<QVariant>() << true)
3583 << (QList<QVariant>() << QVariant(100))
3586 // In the following three cases, test that scarce resources are handled
3587 // correctly for imports.
3588 QTest::newRow("variant: import with no binding")
3589 << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
3590 << false // cannot check detach status.
3593 << QList<QVariant>()
3594 << QList<QVariant>()
3596 QTest::newRow("variant: import with binding without explicit preserve")
3597 << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
3600 << (QStringList() << QLatin1String("scarceResourceCopy"))
3601 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3602 << (QList<QVariant>() << QVariant())
3604 QTest::newRow("variant: import with explicit release after binding evaluation")
3605 << TEST_FILE("scarceResourceCopyImport.variant.qml")
3608 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3609 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3610 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3614 void tst_qdeclarativeecmascript::scarceResources()
3616 QFETCH(QUrl, qmlFile);
3617 QFETCH(bool, readDetachStatus);
3618 QFETCH(bool, expectedDetachStatus);
3619 QFETCH(QStringList, propertyNames);
3620 QFETCH(QVariantList, expectedValidity);
3621 QFETCH(QVariantList, expectedValues);
3622 QFETCH(QStringList, expectedErrors);
3624 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3625 ScarceResourceObject *eo = 0;
3626 QObject *object = 0;
3628 QDeclarativeComponent c(&engine, qmlFile);
3629 object = c.create();
3630 QVERIFY(object != 0);
3631 for (int i = 0; i < propertyNames.size(); ++i) {
3632 QString prop = propertyNames.at(i);
3633 bool validity = expectedValidity.at(i).toBool();
3634 QVariant value = expectedValues.at(i);
3636 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3637 if (value.type() == QVariant::Int) {
3638 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3639 } else if (value.type() == QVariant::Pixmap) {
3640 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3644 if (readDetachStatus) {
3645 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3646 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3649 QVERIFY(ep->scarceResources.isEmpty());
3653 void tst_qdeclarativeecmascript::propertyChangeSlots()
3655 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3656 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3657 QObject *object = component.create();
3658 QVERIFY(object != 0);
3661 // ensure that invalid property names fail properly.
3662 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3663 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3664 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3665 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3666 object = e1.create();
3667 QVERIFY(object == 0);
3670 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3671 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3672 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3673 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3674 object = e2.create();
3675 QVERIFY(object == 0);
3678 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3679 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3680 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3681 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3682 object = e3.create();
3683 QVERIFY(object == 0);
3686 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3687 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3688 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3689 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3690 object = e4.create();
3691 QVERIFY(object == 0);
3695 void tst_qdeclarativeecmascript::propertyVar_data()
3697 QTest::addColumn<QUrl>("qmlFile");
3700 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3701 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3702 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3703 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3704 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3705 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3706 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3707 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3708 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3711 void tst_qdeclarativeecmascript::propertyVar()
3713 QFETCH(QUrl, qmlFile);
3715 QDeclarativeComponent component(&engine, qmlFile);
3716 QObject *object = component.create();
3717 QVERIFY(object != 0);
3719 QCOMPARE(object->property("test").toBool(), true);
3724 // Tests that we can write QVariant values to var properties from C++
3725 void tst_qdeclarativeecmascript::propertyVarCpp()
3727 QObject *object = 0;
3729 // ensure that writing to and reading from a var property from cpp works as required.
3730 // Literal values stored in var properties can be read and written as QVariants
3731 // of a specific type, whereas object values are read as QVariantMaps.
3732 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3733 object = component.create();
3734 QVERIFY(object != 0);
3735 // assign int to property var that currently has int assigned
3736 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3737 QCOMPARE(object->property("varBound"), QVariant(15));
3738 QCOMPARE(object->property("intBound"), QVariant(15));
3739 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3740 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3741 // assign string to property var that current has bool assigned
3742 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3743 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3744 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3745 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3746 // now enforce behaviour when accessing JavaScript objects from cpp.
3747 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3751 static void gc(QDeclarativeEngine &engine)
3753 engine.collectGarbage();
3754 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3757 void tst_qdeclarativeecmascript::propertyVarOwnership()
3759 // Referenced JS objects are not collected
3761 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3762 QObject *object = component.create();
3763 QVERIFY(object != 0);
3764 QCOMPARE(object->property("test").toBool(), false);
3765 QMetaObject::invokeMethod(object, "runTest");
3766 QCOMPARE(object->property("test").toBool(), true);
3769 // Referenced JS objects are not collected
3771 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3772 QObject *object = component.create();
3773 QVERIFY(object != 0);
3774 QCOMPARE(object->property("test").toBool(), false);
3775 QMetaObject::invokeMethod(object, "runTest");
3776 QCOMPARE(object->property("test").toBool(), true);
3779 // Qt objects are not collected until they've been dereferenced
3781 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3782 QObject *object = component.create();
3783 QVERIFY(object != 0);
3785 QCOMPARE(object->property("test2").toBool(), false);
3786 QCOMPARE(object->property("test2").toBool(), false);
3788 QMetaObject::invokeMethod(object, "runTest");
3789 QCOMPARE(object->property("test1").toBool(), true);
3791 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3792 QVERIFY(!referencedObject.isNull());
3794 QVERIFY(!referencedObject.isNull());
3796 QMetaObject::invokeMethod(object, "runTest2");
3797 QCOMPARE(object->property("test2").toBool(), true);
3799 QVERIFY(referencedObject.isNull());
3803 // Self reference does not prevent Qt object collection
3805 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3806 QObject *object = component.create();
3807 QVERIFY(object != 0);
3809 QCOMPARE(object->property("test").toBool(), true);
3811 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3812 QVERIFY(!referencedObject.isNull());
3814 QVERIFY(!referencedObject.isNull());
3816 QMetaObject::invokeMethod(object, "runTest");
3818 QVERIFY(referencedObject.isNull());
3824 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3826 // The childObject has a reference to a different QObject. We want to ensure
3827 // that the different item will not be cleaned up until required. IE, the childObject
3828 // has implicit ownership of the constructed QObject.
3829 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3830 QObject *object = component.create();
3831 QVERIFY(object != 0);
3832 QMetaObject::invokeMethod(object, "assignCircular");
3833 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3834 QObject *rootObject = object->property("vp").value<QObject*>();
3835 QVERIFY(rootObject != 0);
3836 QObject *childObject = rootObject->findChild<QObject*>("text");
3837 QVERIFY(childObject != 0);
3838 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3839 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3840 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3841 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3842 QVERIFY(!qobjectGuard.isNull());
3843 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3844 QVERIFY(!qobjectGuard.isNull());
3845 QMetaObject::invokeMethod(object, "deassignCircular");
3846 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3847 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3851 void tst_qdeclarativeecmascript::propertyVarReparent()
3853 // ensure that nothing breaks if we re-parent objects
3854 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3855 QObject *object = component.create();
3856 QVERIFY(object != 0);
3857 QMetaObject::invokeMethod(object, "assignVarProp");
3858 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3859 QObject *rect = object->property("vp").value<QObject*>();
3860 QObject *text = rect->findChild<QObject*>("textOne");
3861 QObject *text2 = rect->findChild<QObject*>("textTwo");
3862 QWeakPointer<QObject> rectGuard(rect);
3863 QWeakPointer<QObject> textGuard(text);
3864 QWeakPointer<QObject> text2Guard(text2);
3865 QVERIFY(!rectGuard.isNull());
3866 QVERIFY(!textGuard.isNull());
3867 QVERIFY(!text2Guard.isNull());
3868 QCOMPARE(text->property("textCanary").toInt(), 11);
3869 QCOMPARE(text2->property("textCanary").toInt(), 12);
3870 // now construct an image which we will reparent.
3871 QMetaObject::invokeMethod(text2, "constructQObject");
3872 QObject *image = text2->property("vp").value<QObject*>();
3873 QWeakPointer<QObject> imageGuard(image);
3874 QVERIFY(!imageGuard.isNull());
3875 QCOMPARE(image->property("imageCanary").toInt(), 13);
3876 // now reparent the "Image" object (currently, it has JS ownership)
3877 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3878 QMetaObject::invokeMethod(text2, "deassignVp");
3879 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3880 QCOMPARE(text->property("textCanary").toInt(), 11);
3881 QCOMPARE(text2->property("textCanary").toInt(), 22);
3882 QVERIFY(!imageGuard.isNull()); // should still be alive.
3883 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3884 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3885 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3886 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3890 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3892 // sometimes reparenting can cause problems
3893 // (eg, if the ctxt is collected, varproperties are no longer available)
3894 // this test ensures that no crash occurs in that situation.
3895 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3896 QObject *object = component.create();
3897 QVERIFY(object != 0);
3898 QMetaObject::invokeMethod(object, "assignVarProp");
3899 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3900 QObject *rect = object->property("vp").value<QObject*>();
3901 QObject *text = rect->findChild<QObject*>("textOne");
3902 QObject *text2 = rect->findChild<QObject*>("textTwo");
3903 QWeakPointer<QObject> rectGuard(rect);
3904 QWeakPointer<QObject> textGuard(text);
3905 QWeakPointer<QObject> text2Guard(text2);
3906 QVERIFY(!rectGuard.isNull());
3907 QVERIFY(!textGuard.isNull());
3908 QVERIFY(!text2Guard.isNull());
3909 QCOMPARE(text->property("textCanary").toInt(), 11);
3910 QCOMPARE(text2->property("textCanary").toInt(), 12);
3911 // now construct an image which we will reparent.
3912 QMetaObject::invokeMethod(text2, "constructQObject");
3913 QObject *image = text2->property("vp").value<QObject*>();
3914 QWeakPointer<QObject> imageGuard(image);
3915 QVERIFY(!imageGuard.isNull());
3916 QCOMPARE(image->property("imageCanary").toInt(), 13);
3917 // now reparent the "Image" object (currently, it has JS ownership)
3918 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3919 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3920 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3921 QVERIFY(!imageGuard.isNull()); // should still be alive.
3922 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3924 QVERIFY(imageGuard.isNull()); // should now be dead.
3927 void tst_qdeclarativeecmascript::propertyVarCircular()
3929 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3930 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3931 QObject *object = component.create();
3932 QVERIFY(object != 0);
3933 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3934 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3935 QCOMPARE(object->property("canaryInt"), QVariant(5));
3936 QVariant canaryResourceVariant = object->property("canaryResource");
3937 QVERIFY(canaryResourceVariant.isValid());
3938 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3939 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3940 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3941 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3942 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3943 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3944 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3945 QCOMPARE(object->property("canaryInt"), QVariant(2));
3946 QCOMPARE(object->property("canaryResource"), QVariant(1));
3947 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3951 void tst_qdeclarativeecmascript::propertyVarCircular2()
3953 // track deletion of JS-owned parent item with Cpp-owned child
3954 // where the child has a var property referencing its parent.
3955 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3956 QObject *object = component.create();
3957 QVERIFY(object != 0);
3958 QMetaObject::invokeMethod(object, "assignCircular");
3959 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3960 QObject *rootObject = object->property("vp").value<QObject*>();
3961 QVERIFY(rootObject != 0);
3962 QObject *childObject = rootObject->findChild<QObject*>("text");
3963 QVERIFY(childObject != 0);
3964 QWeakPointer<QObject> rootObjectTracker(rootObject);
3965 QVERIFY(!rootObjectTracker.isNull());
3966 QWeakPointer<QObject> childObjectTracker(childObject);
3967 QVERIFY(!childObjectTracker.isNull());
3969 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3970 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3971 QMetaObject::invokeMethod(object, "deassignCircular");
3972 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3973 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3974 QVERIFY(childObjectTracker.isNull()); // should have been collected
3978 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3980 *(int*)(parameter) += 1;
3981 qPersistentDispose(object);
3984 void tst_qdeclarativeecmascript::propertyVarInheritance()
3986 int propertyVarWeakRefCallbackCount = 0;
3988 // enforce behaviour regarding element inheritance - ensure handle disposal.
3989 // The particular component under test here has a chain of references.
3990 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3991 QObject *object = component.create();
3992 QVERIFY(object != 0);
3993 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3994 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3995 // we want to be able to track when the varProperties array of the last metaobject is disposed
3996 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3997 QObject *ico5 = object->property("varProperty").value<QObject*>()->property("inheritanceVarProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3998 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3999 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
4000 v8::Persistent<v8::Value> icoCanaryHandle;
4001 v8::Persistent<v8::Value> ccoCanaryHandle;
4004 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4005 // public function which can return us a handle to something in the varProperties array.
4006 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4007 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4008 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4009 // as the varproperties array of each vmemo still references the resource.
4010 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4011 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4013 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4015 // now we deassign the var prop, which should trigger collection of item subtrees.
4016 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4017 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4018 // ensure that there are only weak handles to the underlying varProperties array remaining.
4020 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4022 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4023 // to what remains are weak, all varProperties arrays must have been collected.
4026 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4028 int propertyVarWeakRefCallbackCount = 0;
4030 // The particular component under test here does NOT have a chain of references; the
4031 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4032 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
4033 QObject *object = component.create();
4034 QVERIFY(object != 0);
4035 QMetaObject::invokeMethod(object, "assignCircular");
4036 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4037 QObject *rootObject = object->property("vp").value<QObject*>();
4038 QVERIFY(rootObject != 0);
4039 QObject *childObject = rootObject->findChild<QObject*>("text");
4040 QVERIFY(childObject != 0);
4041 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4042 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4043 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4046 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4047 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
4048 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4050 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4051 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4053 QMetaObject::invokeMethod(object, "deassignCircular");
4054 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4055 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4059 // Ensure that QObject type conversion works on binding assignment
4060 void tst_qdeclarativeecmascript::elementAssign()
4062 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
4064 QObject *object = component.create();
4065 QVERIFY(object != 0);
4067 QCOMPARE(object->property("test").toBool(), true);
4073 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4075 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
4077 QObject *object = component.create();
4078 QVERIFY(object != 0);
4080 QCOMPARE(object->property("test").toBool(), true);
4086 void tst_qdeclarativeecmascript::objectConversion()
4088 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
4090 QObject *object = component.create();
4091 QVERIFY(object != 0);
4093 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4094 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4101 void tst_qdeclarativeecmascript::booleanConversion()
4103 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
4105 QObject *object = component.create();
4106 QVERIFY(object != 0);
4108 QCOMPARE(object->property("test_true1").toBool(), true);
4109 QCOMPARE(object->property("test_true2").toBool(), true);
4110 QCOMPARE(object->property("test_true3").toBool(), true);
4111 QCOMPARE(object->property("test_true4").toBool(), true);
4112 QCOMPARE(object->property("test_true5").toBool(), true);
4114 QCOMPARE(object->property("test_false1").toBool(), false);
4115 QCOMPARE(object->property("test_false2").toBool(), false);
4116 QCOMPARE(object->property("test_false3").toBool(), false);
4121 void tst_qdeclarativeecmascript::handleReferenceManagement()
4126 // Linear QObject reference
4127 QDeclarativeEngine hrmEngine;
4128 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
4129 QObject *object = component.create();
4130 QVERIFY(object != 0);
4131 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4132 cro->setEngine(&hrmEngine);
4133 cro->setDtorCount(&dtorCount);
4134 QMetaObject::invokeMethod(object, "createReference");
4136 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4138 hrmEngine.collectGarbage();
4139 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4140 QCOMPARE(dtorCount, 3);
4145 // Circular QObject reference
4146 QDeclarativeEngine hrmEngine;
4147 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
4148 QObject *object = component.create();
4149 QVERIFY(object != 0);
4150 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4151 cro->setEngine(&hrmEngine);
4152 cro->setDtorCount(&dtorCount);
4153 QMetaObject::invokeMethod(object, "circularReference");
4155 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4157 hrmEngine.collectGarbage();
4158 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4159 QCOMPARE(dtorCount, 3);
4164 // Linear handle reference
4165 QDeclarativeEngine hrmEngine;
4166 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4167 QObject *object = component.create();
4168 QVERIFY(object != 0);
4169 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4171 crh->setEngine(&hrmEngine);
4172 crh->setDtorCount(&dtorCount);
4173 QMetaObject::invokeMethod(object, "createReference");
4174 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4175 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4176 QVERIFY(first != 0);
4177 QVERIFY(second != 0);
4178 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4179 // now we have to reparent second and make second owned by JS.
4180 second->setParent(0);
4181 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4183 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4185 hrmEngine.collectGarbage();
4186 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4187 QCOMPARE(dtorCount, 3);
4192 // Circular handle reference
4193 QDeclarativeEngine hrmEngine;
4194 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
4195 QObject *object = component.create();
4196 QVERIFY(object != 0);
4197 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4199 crh->setEngine(&hrmEngine);
4200 crh->setDtorCount(&dtorCount);
4201 QMetaObject::invokeMethod(object, "circularReference");
4202 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4203 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4204 QVERIFY(first != 0);
4205 QVERIFY(second != 0);
4206 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4207 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4208 // now we have to reparent and change ownership.
4209 first->setParent(0);
4210 second->setParent(0);
4211 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4212 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4214 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4216 hrmEngine.collectGarbage();
4217 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4218 QCOMPARE(dtorCount, 3);
4223 // multiple engine interaction - linear reference
4224 QDeclarativeEngine hrmEngine1;
4225 QDeclarativeEngine hrmEngine2;
4226 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4227 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4228 QObject *object1 = component1.create();
4229 QObject *object2 = component2.create();
4230 QVERIFY(object1 != 0);
4231 QVERIFY(object2 != 0);
4232 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4233 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4236 crh1->setEngine(&hrmEngine1);
4237 crh2->setEngine(&hrmEngine2);
4238 crh1->setDtorCount(&dtorCount);
4239 crh2->setDtorCount(&dtorCount);
4240 QMetaObject::invokeMethod(object1, "createReference");
4241 QMetaObject::invokeMethod(object2, "createReference");
4242 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4243 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4244 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4245 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4246 QVERIFY(first1 != 0);
4247 QVERIFY(second1 != 0);
4248 QVERIFY(first2 != 0);
4249 QVERIFY(second2 != 0);
4250 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4251 // now we have to reparent second2 and make second2 owned by JS.
4252 second2->setParent(0);
4253 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4255 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4256 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4259 hrmEngine1.collectGarbage();
4260 hrmEngine2.collectGarbage();
4261 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4262 QCOMPARE(dtorCount, 6);
4267 // multiple engine interaction - circular reference
4268 QDeclarativeEngine hrmEngine1;
4269 QDeclarativeEngine hrmEngine2;
4270 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4271 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4272 QObject *object1 = component1.create();
4273 QObject *object2 = component2.create();
4274 QVERIFY(object1 != 0);
4275 QVERIFY(object2 != 0);
4276 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4277 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4280 crh1->setEngine(&hrmEngine1);
4281 crh2->setEngine(&hrmEngine2);
4282 crh1->setDtorCount(&dtorCount);
4283 crh2->setDtorCount(&dtorCount);
4284 QMetaObject::invokeMethod(object1, "createReference");
4285 QMetaObject::invokeMethod(object2, "createReference");
4286 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4287 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4288 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4289 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4290 QVERIFY(first1 != 0);
4291 QVERIFY(second1 != 0);
4292 QVERIFY(first2 != 0);
4293 QVERIFY(second2 != 0);
4294 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4295 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4296 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4297 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4298 // now we have to reparent and change ownership to JS.
4299 first1->setParent(0);
4300 second1->setParent(0);
4301 first2->setParent(0);
4302 second2->setParent(0);
4303 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4304 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4305 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4306 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4308 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4309 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4312 hrmEngine1.collectGarbage();
4313 hrmEngine2.collectGarbage();
4314 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4315 QCOMPARE(dtorCount, 6);
4320 // multiple engine interaction - linear reference with engine deletion
4321 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4322 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4323 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4324 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4325 QObject *object1 = component1.create();
4326 QObject *object2 = component2.create();
4327 QVERIFY(object1 != 0);
4328 QVERIFY(object2 != 0);
4329 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4330 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4333 crh1->setEngine(hrmEngine1);
4334 crh2->setEngine(hrmEngine2);
4335 crh1->setDtorCount(&dtorCount);
4336 crh2->setDtorCount(&dtorCount);
4337 QMetaObject::invokeMethod(object1, "createReference");
4338 QMetaObject::invokeMethod(object2, "createReference");
4339 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4340 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4341 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4342 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4343 QVERIFY(first1 != 0);
4344 QVERIFY(second1 != 0);
4345 QVERIFY(first2 != 0);
4346 QVERIFY(second2 != 0);
4347 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4348 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4349 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4350 // now we have to reparent and change ownership to JS.
4351 first1->setParent(crh1);
4352 second1->setParent(0);
4353 first2->setParent(0);
4354 second2->setParent(0);
4355 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4356 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4357 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4359 QCOMPARE(dtorCount, 0);
4362 QCOMPARE(dtorCount, 0);
4365 hrmEngine1->collectGarbage();
4366 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4367 QCOMPARE(dtorCount, 6);
4372 void tst_qdeclarativeecmascript::stringArg()
4374 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4375 QObject *object = component.create();
4376 QVERIFY(object != 0);
4377 QMetaObject::invokeMethod(object, "success");
4378 QVERIFY(object->property("returnValue").toBool());
4380 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4381 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4382 QMetaObject::invokeMethod(object, "failure");
4383 QVERIFY(object->property("returnValue").toBool());
4388 void tst_qdeclarativeecmascript::readonlyDeclaration()
4390 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4392 QObject *object = component.create();
4393 QVERIFY(object != 0);
4395 QCOMPARE(object->property("test").toBool(), true);
4400 Q_DECLARE_METATYPE(QList<int>)
4401 Q_DECLARE_METATYPE(QList<qreal>)
4402 Q_DECLARE_METATYPE(QList<bool>)
4403 Q_DECLARE_METATYPE(QList<QString>)
4404 Q_DECLARE_METATYPE(QList<QUrl>)
4405 void tst_qdeclarativeecmascript::sequenceConversionRead()
4408 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4409 QDeclarativeComponent component(&engine, qmlFile);
4410 QObject *object = component.create();
4411 QVERIFY(object != 0);
4412 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4415 QMetaObject::invokeMethod(object, "readSequences");
4416 QList<int> intList; intList << 1 << 2 << 3 << 4;
4417 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4418 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4419 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4420 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4421 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4422 QList<bool> boolList; boolList << true << false << true << false;
4423 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4424 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4425 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4426 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4427 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4428 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4429 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4430 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4431 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4432 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4433 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4435 QMetaObject::invokeMethod(object, "readSequenceElements");
4436 QCOMPARE(object->property("intVal").toInt(), 2);
4437 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4438 QCOMPARE(object->property("boolVal").toBool(), false);
4439 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4440 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4441 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4443 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4444 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4446 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4447 QDeclarativeProperty seqProp(seq, "intListProperty");
4448 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4449 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4450 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4452 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4453 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4459 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4460 QDeclarativeComponent component(&engine, qmlFile);
4461 QObject *object = component.create();
4462 QVERIFY(object != 0);
4463 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4466 // we haven't registered QList<QPoint> as a sequence type.
4467 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4468 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4469 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4470 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4472 QMetaObject::invokeMethod(object, "performTest");
4474 // QList<QPoint> has not been registered as a sequence type.
4475 QCOMPARE(object->property("pointListLength").toInt(), 0);
4476 QVERIFY(!object->property("pointList").isValid());
4477 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4478 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4479 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4485 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4488 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4489 QDeclarativeComponent component(&engine, qmlFile);
4490 QObject *object = component.create();
4491 QVERIFY(object != 0);
4492 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4495 QMetaObject::invokeMethod(object, "writeSequences");
4496 QCOMPARE(object->property("success").toBool(), true);
4498 QMetaObject::invokeMethod(object, "writeSequenceElements");
4499 QCOMPARE(object->property("success").toBool(), true);
4501 QMetaObject::invokeMethod(object, "writeOtherElements");
4502 QCOMPARE(object->property("success").toBool(), true);
4504 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4505 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4511 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4512 QDeclarativeComponent component(&engine, qmlFile);
4513 QObject *object = component.create();
4514 QVERIFY(object != 0);
4515 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4518 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4519 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4520 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4522 QMetaObject::invokeMethod(object, "performTest");
4524 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4525 QCOMPARE(seq->pointListProperty(), pointList);
4531 void tst_qdeclarativeecmascript::sequenceConversionArray()
4533 // ensure that in JS the returned sequences act just like normal JS Arrays.
4534 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4535 QDeclarativeComponent component(&engine, qmlFile);
4536 QObject *object = component.create();
4537 QVERIFY(object != 0);
4538 QMetaObject::invokeMethod(object, "indexedAccess");
4539 QVERIFY(object->property("success").toBool());
4540 QMetaObject::invokeMethod(object, "arrayOperations");
4541 QVERIFY(object->property("success").toBool());
4542 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4543 QVERIFY(object->property("success").toBool());
4544 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4545 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4549 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4551 // ensure that sequence conversion operations work correctly in a worker thread
4552 // and that serialisation between the main and worker thread succeeds.
4553 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4554 QDeclarativeComponent component(&engine, qmlFile);
4555 QObject *object = component.create();
4556 QVERIFY(object != 0);
4558 QMetaObject::invokeMethod(object, "testIntSequence");
4559 QTRY_VERIFY(object->property("finished").toBool());
4560 QVERIFY(object->property("success").toBool());
4562 QMetaObject::invokeMethod(object, "testQrealSequence");
4563 QTRY_VERIFY(object->property("finished").toBool());
4564 QVERIFY(object->property("success").toBool());
4566 QMetaObject::invokeMethod(object, "testBoolSequence");
4567 QTRY_VERIFY(object->property("finished").toBool());
4568 QVERIFY(object->property("success").toBool());
4570 QMetaObject::invokeMethod(object, "testStringSequence");
4571 QTRY_VERIFY(object->property("finished").toBool());
4572 QVERIFY(object->property("success").toBool());
4574 QMetaObject::invokeMethod(object, "testQStringSequence");
4575 QTRY_VERIFY(object->property("finished").toBool());
4576 QVERIFY(object->property("success").toBool());
4578 QMetaObject::invokeMethod(object, "testUrlSequence");
4579 QTRY_VERIFY(object->property("finished").toBool());
4580 QVERIFY(object->property("success").toBool());
4582 QMetaObject::invokeMethod(object, "testVariantSequence");
4583 QTRY_VERIFY(object->property("finished").toBool());
4584 QVERIFY(object->property("success").toBool());
4589 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4592 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4593 QDeclarativeComponent component(&engine, qmlFile);
4594 QObject *object = component.create();
4595 QVERIFY(object != 0);
4596 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4597 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4598 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4599 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4600 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4605 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4606 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4607 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4608 QDeclarativeComponent component(&engine, qmlFile);
4609 QObject *object = component.create();
4610 QVERIFY(object != 0);
4615 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4617 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4618 QDeclarativeComponent component(&engine, qmlFile);
4619 QObject *object = component.create();
4620 QVERIFY(object != 0);
4621 QMetaObject::invokeMethod(object, "testCopySequences");
4622 QCOMPARE(object->property("success").toBool(), true);
4623 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4624 QCOMPARE(object->property("success").toBool(), true);
4625 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4626 QCOMPARE(object->property("success").toBool(), true);
4630 void tst_qdeclarativeecmascript::assignSequenceTypes()
4632 // test binding array to sequence type property
4634 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.1.qml"));
4635 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4636 QVERIFY(object != 0);
4637 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4638 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4639 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4640 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4641 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4642 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4646 // test binding literal to sequence type property
4648 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.2.qml"));
4649 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4650 QVERIFY(object != 0);
4651 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4652 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4653 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4654 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4655 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4656 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4660 // test binding single value to sequence type property
4662 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.3.qml"));
4663 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4664 QVERIFY(object != 0);
4665 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4666 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4667 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4668 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4672 // test assigning array to sequence type property in js function
4674 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.4.qml"));
4675 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4676 QVERIFY(object != 0);
4677 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4678 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4679 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4680 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4681 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4682 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4686 // test assigning literal to sequence type property in js function
4688 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.5.qml"));
4689 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4690 QVERIFY(object != 0);
4691 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4692 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4693 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4694 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4695 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4696 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4700 // test assigning single value to sequence type property in js function
4702 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.6.qml"));
4703 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4704 QVERIFY(object != 0);
4705 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4706 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4707 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4708 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4713 // Test that assigning a null object works
4714 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4715 void tst_qdeclarativeecmascript::nullObjectBinding()
4717 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4719 QObject *object = component.create();
4720 QVERIFY(object != 0);
4722 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4727 // Test that bindings don't evaluate once the engine has been destroyed
4728 void tst_qdeclarativeecmascript::deletedEngine()
4730 QDeclarativeEngine *engine = new QDeclarativeEngine;
4731 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4733 QObject *object = component.create();
4734 QVERIFY(object != 0);
4736 QCOMPARE(object->property("a").toInt(), 39);
4737 object->setProperty("b", QVariant(9));
4738 QCOMPARE(object->property("a").toInt(), 117);
4742 QCOMPARE(object->property("a").toInt(), 117);
4743 object->setProperty("b", QVariant(10));
4744 QCOMPARE(object->property("a").toInt(), 117);
4749 // Test the crashing part of QTBUG-9705
4750 void tst_qdeclarativeecmascript::libraryScriptAssert()
4752 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4754 QObject *object = component.create();
4755 QVERIFY(object != 0);
4760 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4762 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4764 QObject *object = component.create();
4765 QVERIFY(object != 0);
4767 QCOMPARE(object->property("test1").toInt(), 10);
4768 QCOMPARE(object->property("test2").toInt(), 11);
4770 object->setProperty("runTest", true);
4772 QCOMPARE(object->property("test1"), QVariant());
4773 QCOMPARE(object->property("test2"), QVariant());
4779 void tst_qdeclarativeecmascript::qtbug_9792()
4781 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4783 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4785 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4786 QVERIFY(object != 0);
4788 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4789 object->basicSignal();
4793 transientErrorsMsgCount = 0;
4794 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4796 object->basicSignal();
4798 qInstallMsgHandler(old);
4800 QCOMPARE(transientErrorsMsgCount, 0);
4805 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4806 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4808 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4810 QObject *o = component.create();
4813 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4814 QVERIFY(nested != 0);
4816 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4819 nested = qvariant_cast<QObject *>(o->property("object"));
4820 QVERIFY(nested == 0);
4822 // If the bug is present, the next line will crash
4826 // Test that we shut down without stupid warnings
4827 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4830 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4832 QObject *o = component.create();
4834 transientErrorsMsgCount = 0;
4835 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4839 qInstallMsgHandler(old);
4841 QCOMPARE(transientErrorsMsgCount, 0);
4846 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4848 QObject *o = component.create();
4850 transientErrorsMsgCount = 0;
4851 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4855 qInstallMsgHandler(old);
4857 QCOMPARE(transientErrorsMsgCount, 0);
4861 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4864 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4866 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4869 QVERIFY(o->objectProperty() != 0);
4871 o->setProperty("runTest", true);
4873 QVERIFY(o->objectProperty() == 0);
4879 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4881 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4884 QVERIFY(o->objectProperty() == 0);
4890 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4892 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4894 QString url = component.url().toString();
4895 QString warning = url + ":4: Unable to assign a function to a property.";
4896 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4898 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4901 QVERIFY(!o->property("a").isValid());
4906 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4908 QFETCH(QString, triggerProperty);
4910 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4911 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4913 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4915 QVERIFY(!o->property("a").isValid());
4917 o->setProperty("aNumber", QVariant(5));
4918 o->setProperty(triggerProperty.toUtf8().constData(), true);
4919 QCOMPARE(o->property("a"), QVariant(50));
4921 o->setProperty("aNumber", QVariant(10));
4922 QCOMPARE(o->property("a"), QVariant(100));
4927 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4929 QTest::addColumn<QString>("triggerProperty");
4931 QTest::newRow("assign to property") << "assignToProperty";
4932 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4934 QTest::newRow("assign to value type") << "assignToValueType";
4936 QTest::newRow("use 'this'") << "assignWithThis";
4937 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4940 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4942 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4943 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4945 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4947 QVERIFY(!o->property("a").isValid());
4949 o->setProperty("assignFuncWithoutReturn", true);
4950 QVERIFY(!o->property("a").isValid());
4952 QString url = component.url().toString();
4953 QString warning = url + ":67: Unable to assign QString to int";
4954 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4955 o->setProperty("assignWrongType", true);
4957 warning = url + ":71: Unable to assign QString to int";
4958 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4959 o->setProperty("assignWrongTypeToValueType", true);
4964 void tst_qdeclarativeecmascript::eval()
4966 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4968 QObject *o = component.create();
4971 QCOMPARE(o->property("test1").toBool(), true);
4972 QCOMPARE(o->property("test2").toBool(), true);
4973 QCOMPARE(o->property("test3").toBool(), true);
4974 QCOMPARE(o->property("test4").toBool(), true);
4975 QCOMPARE(o->property("test5").toBool(), true);
4980 void tst_qdeclarativeecmascript::function()
4982 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4984 QObject *o = component.create();
4987 QCOMPARE(o->property("test1").toBool(), true);
4988 QCOMPARE(o->property("test2").toBool(), true);
4989 QCOMPARE(o->property("test3").toBool(), true);
4994 // Test the "Qt.include" method
4995 void tst_qdeclarativeecmascript::include()
4997 // Non-library relative include
4999 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
5000 QObject *o = component.create();
5003 QCOMPARE(o->property("test0").toInt(), 99);
5004 QCOMPARE(o->property("test1").toBool(), true);
5005 QCOMPARE(o->property("test2").toBool(), true);
5006 QCOMPARE(o->property("test2_1").toBool(), true);
5007 QCOMPARE(o->property("test3").toBool(), true);
5008 QCOMPARE(o->property("test3_1").toBool(), true);
5013 // Library relative include
5015 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
5016 QObject *o = component.create();
5019 QCOMPARE(o->property("test0").toInt(), 99);
5020 QCOMPARE(o->property("test1").toBool(), true);
5021 QCOMPARE(o->property("test2").toBool(), true);
5022 QCOMPARE(o->property("test2_1").toBool(), true);
5023 QCOMPARE(o->property("test3").toBool(), true);
5024 QCOMPARE(o->property("test3_1").toBool(), true);
5031 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
5032 QObject *o = component.create();
5035 QCOMPARE(o->property("test1").toBool(), true);
5036 QCOMPARE(o->property("test2").toBool(), true);
5037 QCOMPARE(o->property("test3").toBool(), true);
5038 QCOMPARE(o->property("test4").toBool(), true);
5039 QCOMPARE(o->property("test5").toBool(), true);
5040 QCOMPARE(o->property("test6").toBool(), true);
5045 // Including file with ".pragma library"
5047 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
5048 QObject *o = component.create();
5050 QCOMPARE(o->property("test1").toInt(), 100);
5057 TestHTTPServer server(8111);
5058 QVERIFY(server.isValid());
5059 server.serveDirectory(TESTDATA(""));
5061 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
5062 QObject *o = component.create();
5065 QTRY_VERIFY(o->property("done").toBool() == true);
5066 QTRY_VERIFY(o->property("done2").toBool() == true);
5068 QCOMPARE(o->property("test1").toBool(), true);
5069 QCOMPARE(o->property("test2").toBool(), true);
5070 QCOMPARE(o->property("test3").toBool(), true);
5071 QCOMPARE(o->property("test4").toBool(), true);
5072 QCOMPARE(o->property("test5").toBool(), true);
5074 QCOMPARE(o->property("test6").toBool(), true);
5075 QCOMPARE(o->property("test7").toBool(), true);
5076 QCOMPARE(o->property("test8").toBool(), true);
5077 QCOMPARE(o->property("test9").toBool(), true);
5078 QCOMPARE(o->property("test10").toBool(), true);
5085 TestHTTPServer server(8111);
5086 QVERIFY(server.isValid());
5087 server.serveDirectory(TESTDATA(""));
5089 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
5090 QObject *o = component.create();
5093 QTRY_VERIFY(o->property("done").toBool() == true);
5095 QCOMPARE(o->property("test1").toBool(), true);
5096 QCOMPARE(o->property("test2").toBool(), true);
5097 QCOMPARE(o->property("test3").toBool(), true);
5103 void tst_qdeclarativeecmascript::signalHandlers()
5105 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
5106 QObject *o = component.create();
5109 QVERIFY(o->property("count").toInt() == 0);
5110 QMetaObject::invokeMethod(o, "testSignalCall");
5111 QCOMPARE(o->property("count").toInt(), 1);
5113 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5114 QCOMPARE(o->property("count").toInt(), 1);
5115 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5117 QVERIFY(o->property("funcCount").toInt() == 0);
5118 QMetaObject::invokeMethod(o, "testSignalConnection");
5119 QCOMPARE(o->property("funcCount").toInt(), 1);
5121 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5122 QCOMPARE(o->property("funcCount").toInt(), 2);
5124 QMetaObject::invokeMethod(o, "testSignalDefined");
5125 QCOMPARE(o->property("definedResult").toBool(), true);
5127 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5128 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5133 void tst_qdeclarativeecmascript::qtbug_10696()
5135 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
5136 QObject *o = component.create();
5141 void tst_qdeclarativeecmascript::qtbug_11606()
5143 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
5144 QObject *o = component.create();
5146 QCOMPARE(o->property("test").toBool(), true);
5150 void tst_qdeclarativeecmascript::qtbug_11600()
5152 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
5153 QObject *o = component.create();
5155 QCOMPARE(o->property("test").toBool(), true);
5159 void tst_qdeclarativeecmascript::qtbug_21864()
5161 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21864.qml"));
5162 QObject *o = component.create();
5164 QCOMPARE(o->property("test").toBool(), true);
5168 // Reading and writing non-scriptable properties should fail
5169 void tst_qdeclarativeecmascript::nonscriptable()
5171 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
5172 QObject *o = component.create();
5174 QCOMPARE(o->property("readOk").toBool(), true);
5175 QCOMPARE(o->property("writeOk").toBool(), true);
5179 // deleteLater() should not be callable from QML
5180 void tst_qdeclarativeecmascript::deleteLater()
5182 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
5183 QObject *o = component.create();
5185 QCOMPARE(o->property("test").toBool(), true);
5189 void tst_qdeclarativeecmascript::in()
5191 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
5192 QObject *o = component.create();
5194 QCOMPARE(o->property("test1").toBool(), true);
5195 QCOMPARE(o->property("test2").toBool(), true);
5199 void tst_qdeclarativeecmascript::typeOf()
5201 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
5203 // These warnings should not happen once QTBUG-21864 is fixed
5204 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5205 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5207 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5208 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5210 QObject *o = component.create();
5213 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5214 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5215 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5216 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5217 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5218 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5219 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5220 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5221 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5222 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5227 void tst_qdeclarativeecmascript::sharedAttachedObject()
5229 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
5230 QObject *o = component.create();
5232 QCOMPARE(o->property("test1").toBool(), true);
5233 QCOMPARE(o->property("test2").toBool(), true);
5238 void tst_qdeclarativeecmascript::objectName()
5240 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
5241 QObject *o = component.create();
5244 QCOMPARE(o->property("test1").toString(), QString("hello"));
5245 QCOMPARE(o->property("test2").toString(), QString("ell"));
5247 o->setObjectName("world");
5249 QCOMPARE(o->property("test1").toString(), QString("world"));
5250 QCOMPARE(o->property("test2").toString(), QString("orl"));
5255 void tst_qdeclarativeecmascript::writeRemovesBinding()
5257 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
5258 QObject *o = component.create();
5261 QCOMPARE(o->property("test").toBool(), true);
5266 // Test bindings assigned to alias properties actually assign to the alias' target
5267 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5269 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
5270 QObject *o = component.create();
5273 QCOMPARE(o->property("test").toBool(), true);
5278 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5279 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5282 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
5283 QObject *o = component.create();
5286 QCOMPARE(o->property("test").toBool(), true);
5292 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
5293 QObject *o = component.create();
5296 QCOMPARE(o->property("test").toBool(), true);
5302 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
5303 QObject *o = component.create();
5306 QCOMPARE(o->property("test").toBool(), true);
5312 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5313 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5316 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
5317 QObject *o = component.create();
5320 QCOMPARE(o->property("test").toBool(), true);
5326 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
5327 QObject *o = component.create();
5330 QCOMPARE(o->property("test").toBool(), true);
5336 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
5337 QObject *o = component.create();
5340 QCOMPARE(o->property("test").toBool(), true);
5346 // Allow an alais to a composite element
5348 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5350 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
5352 QObject *object = component.create();
5353 QVERIFY(object != 0);
5358 void tst_qdeclarativeecmascript::qtbug_20344()
5360 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
5362 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5363 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5365 QObject *object = component.create();
5366 QVERIFY(object != 0);
5371 void tst_qdeclarativeecmascript::revisionErrors()
5374 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
5375 QString url = component.url().toString();
5377 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5378 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5379 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5381 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5382 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5383 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5384 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5385 QVERIFY(object != 0);
5389 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
5390 QString url = component.url().toString();
5392 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5393 // method2, prop2 from MyRevisionedClass not available
5394 // method4, prop4 from MyRevisionedSubclass not available
5395 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5396 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5397 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5398 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5399 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5401 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5402 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5403 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5404 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5405 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5406 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5407 QVERIFY(object != 0);
5411 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5412 QString url = component.url().toString();
5414 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5415 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5416 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5417 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5418 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5419 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5420 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5421 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5422 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5423 QVERIFY(object != 0);
5428 void tst_qdeclarativeecmascript::revision()
5431 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5432 QString url = component.url().toString();
5434 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5435 QVERIFY(object != 0);
5439 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5440 QString url = component.url().toString();
5442 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5443 QVERIFY(object != 0);
5447 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5448 QString url = component.url().toString();
5450 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5451 QVERIFY(object != 0);
5454 // Test that non-root classes can resolve revisioned methods
5456 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5458 QObject *object = component.create();
5459 QVERIFY(object != 0);
5460 QCOMPARE(object->property("test").toReal(), 11.);
5465 void tst_qdeclarativeecmascript::realToInt()
5467 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5468 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5469 QVERIFY(object != 0);
5471 QMetaObject::invokeMethod(object, "test1");
5472 QCOMPARE(object->value(), int(4));
5473 QMetaObject::invokeMethod(object, "test2");
5474 QCOMPARE(object->value(), int(8));
5477 void tst_qdeclarativeecmascript::urlProperty()
5480 QDeclarativeComponent component(&engine, TEST_FILE("urlProperty.1.qml"));
5481 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5482 QVERIFY(object != 0);
5483 object->setStringProperty("http://qt-project.org");
5484 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5485 QCOMPARE(object->intProperty(), 123);
5486 QCOMPARE(object->value(), 1);
5487 QCOMPARE(object->property("result").toBool(), true);
5491 void tst_qdeclarativeecmascript::dynamicString()
5493 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5494 QObject *object = component.create();
5495 QVERIFY(object != 0);
5496 QCOMPARE(object->property("stringProperty").toString(),
5497 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5500 void tst_qdeclarativeecmascript::automaticSemicolon()
5502 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5503 QObject *object = component.create();
5504 QVERIFY(object != 0);
5507 void tst_qdeclarativeecmascript::unaryExpression()
5509 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5510 QObject *object = component.create();
5511 QVERIFY(object != 0);
5514 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5515 void tst_qdeclarativeecmascript::doubleEvaluate()
5517 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5518 QObject *object = component.create();
5519 QVERIFY(object != 0);
5520 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5522 QCOMPARE(wc->count(), 1);
5524 wc->setProperty("x", 9);
5526 QCOMPARE(wc->count(), 2);
5531 static QStringList messages;
5532 static void captureMsgHandler(QtMsgType, const char *msg)
5534 messages.append(QLatin1String(msg));
5537 void tst_qdeclarativeecmascript::nonNotifyable()
5539 QV4Compiler::enableV4(false);
5540 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5541 QV4Compiler::enableV4(true);
5543 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5545 QObject *object = component.create();
5546 qInstallMsgHandler(old);
5548 QVERIFY(object != 0);
5550 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5551 component.url().toString() +
5552 QLatin1String(":5 depends on non-NOTIFYable properties:");
5553 QString expected2 = QLatin1String(" ") +
5554 QLatin1String(object->metaObject()->className()) +
5555 QLatin1String("::value");
5557 QCOMPARE(messages.length(), 2);
5558 QCOMPARE(messages.at(0), expected1);
5559 QCOMPARE(messages.at(1), expected2);
5564 void tst_qdeclarativeecmascript::forInLoop()
5566 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5567 QObject *object = component.create();
5568 QVERIFY(object != 0);
5570 QMetaObject::invokeMethod(object, "listProperty");
5572 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5573 QCOMPARE(r.size(), 3);
5574 QCOMPARE(r[0],QLatin1String("0=obj1"));
5575 QCOMPARE(r[1],QLatin1String("1=obj2"));
5576 QCOMPARE(r[2],QLatin1String("2=obj3"));
5578 //TODO: should test for in loop for other objects (such as QObjects) as well.
5583 // An object the binding depends on is deleted while the binding is still running
5584 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5586 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5587 QObject *object = component.create();
5588 QVERIFY(object != 0);
5592 void tst_qdeclarativeecmascript::qtbug_22679()
5595 object.setStringProperty(QLatin1String("Please work correctly"));
5596 engine.rootContext()->setContextProperty("contextProp", &object);
5598 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5599 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5600 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5602 QObject *o = component.create();
5604 QCOMPARE(warningsSpy.count(), 0);
5608 void tst_qdeclarativeecmascript::qtbug_22843_data()
5610 QTest::addColumn<bool>("library");
5612 QTest::newRow("without .pragma library") << false;
5613 QTest::newRow("with .pragma library") << true;
5616 void tst_qdeclarativeecmascript::qtbug_22843()
5618 QFETCH(bool, library);
5620 QString fileName("qtbug_22843");
5622 fileName += QLatin1String(".library");
5623 fileName += QLatin1String(".qml");
5625 QDeclarativeComponent component(&engine, TEST_FILE(fileName));
5626 QString url = component.url().toString();
5627 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5628 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5630 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5631 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5632 for (int x = 0; x < 3; ++x) {
5633 warningsSpy.clear();
5634 // For libraries, only the first import attempt should produce a
5635 // SyntaxError warning; subsequent component creation should not
5636 // attempt to reload the script.
5637 bool expectSyntaxError = !library || (x == 0);
5638 if (expectSyntaxError)
5639 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5640 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5641 QObject *object = component.create();
5642 QVERIFY(object != 0);
5643 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5649 void tst_qdeclarativeecmascript::switchStatement()
5652 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.1.qml"));
5653 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5654 QVERIFY(object != 0);
5656 // `object->value()' is the number of executed statements
5658 object->setStringProperty("A");
5659 QCOMPARE(object->value(), 5);
5661 object->setStringProperty("S");
5662 QCOMPARE(object->value(), 3);
5664 object->setStringProperty("D");
5665 QCOMPARE(object->value(), 3);
5667 object->setStringProperty("F");
5668 QCOMPARE(object->value(), 4);
5670 object->setStringProperty("something else");
5671 QCOMPARE(object->value(), 1);
5675 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.2.qml"));
5676 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5677 QVERIFY(object != 0);
5679 // `object->value()' is the number of executed statements
5681 object->setStringProperty("A");
5682 QCOMPARE(object->value(), 5);
5684 object->setStringProperty("S");
5685 QCOMPARE(object->value(), 3);
5687 object->setStringProperty("D");
5688 QCOMPARE(object->value(), 3);
5690 object->setStringProperty("F");
5691 QCOMPARE(object->value(), 3);
5693 object->setStringProperty("something else");
5694 QCOMPARE(object->value(), 4);
5698 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.3.qml"));
5699 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5700 QVERIFY(object != 0);
5702 // `object->value()' is the number of executed statements
5704 object->setStringProperty("A");
5705 QCOMPARE(object->value(), 5);
5707 object->setStringProperty("S");
5708 QCOMPARE(object->value(), 3);
5710 object->setStringProperty("D");
5711 QCOMPARE(object->value(), 3);
5713 object->setStringProperty("F");
5714 QCOMPARE(object->value(), 3);
5716 object->setStringProperty("something else");
5717 QCOMPARE(object->value(), 6);
5721 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.4.qml"));
5723 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5724 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5726 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5727 QVERIFY(object != 0);
5729 // `object->value()' is the number of executed statements
5731 object->setStringProperty("A");
5732 QCOMPARE(object->value(), 5);
5734 object->setStringProperty("S");
5735 QCOMPARE(object->value(), 3);
5737 object->setStringProperty("D");
5738 QCOMPARE(object->value(), 3);
5740 object->setStringProperty("F");
5741 QCOMPARE(object->value(), 3);
5743 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5745 object->setStringProperty("something else");
5749 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.5.qml"));
5750 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5751 QVERIFY(object != 0);
5753 // `object->value()' is the number of executed statements
5755 object->setStringProperty("A");
5756 QCOMPARE(object->value(), 1);
5758 object->setStringProperty("S");
5759 QCOMPARE(object->value(), 1);
5761 object->setStringProperty("D");
5762 QCOMPARE(object->value(), 1);
5764 object->setStringProperty("F");
5765 QCOMPARE(object->value(), 1);
5767 object->setStringProperty("something else");
5768 QCOMPARE(object->value(), 1);
5772 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.6.qml"));
5773 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5774 QVERIFY(object != 0);
5776 // `object->value()' is the number of executed statements
5778 object->setStringProperty("A");
5779 QCOMPARE(object->value(), 123);
5781 object->setStringProperty("S");
5782 QCOMPARE(object->value(), 123);
5784 object->setStringProperty("D");
5785 QCOMPARE(object->value(), 321);
5787 object->setStringProperty("F");
5788 QCOMPARE(object->value(), 321);
5790 object->setStringProperty("something else");
5791 QCOMPARE(object->value(), 0);
5795 void tst_qdeclarativeecmascript::withStatement()
5798 QDeclarativeComponent component(&engine, TEST_FILE("withStatement.1.qml"));
5799 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5800 QVERIFY(object != 0);
5802 QCOMPARE(object->value(), 123);
5806 void tst_qdeclarativeecmascript::tryStatement()
5809 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.1.qml"));
5810 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5811 QVERIFY(object != 0);
5813 QCOMPARE(object->value(), 123);
5817 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.2.qml"));
5818 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5819 QVERIFY(object != 0);
5821 QCOMPARE(object->value(), 321);
5825 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.3.qml"));
5826 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5827 QVERIFY(object != 0);
5829 QCOMPARE(object->value(), 1);
5833 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.4.qml"));
5834 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5835 QVERIFY(object != 0);
5837 QCOMPARE(object->value(), 1);
5841 QTEST_MAIN(tst_qdeclarativeecmascript)
5843 #include "tst_qdeclarativeecmascript.moc"