1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** 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
65 class tst_qdeclarativeecmascript : public QDeclarativeDataTest
69 tst_qdeclarativeecmascript() {}
73 void assignBasicTypes();
74 void idShortcutInvalidates();
75 void boolPropertiesEvaluateAsBool();
77 void signalAssignment();
79 void basicExpressions();
80 void basicExpressions_data();
81 void arrayExpressions();
82 void contextPropertiesTriggerReeval();
83 void objectPropertiesTriggerReeval();
84 void deferredProperties();
85 void deferredPropertiesErrors();
86 void extensionObjects();
87 void overrideExtensionProperties();
88 void attachedProperties();
90 void valueTypeFunctions();
91 void constantsOverrideBindings();
92 void outerBindingOverridesInnerBinding();
93 void aliasPropertyAndBinding();
94 void aliasPropertyReset();
95 void nonExistentAttachedObject();
98 void signalParameterTypes();
99 void objectsCompareAsEqual();
100 void dynamicCreation_data();
101 void dynamicCreation();
102 void dynamicDestruction();
103 void objectToString();
104 void objectHasOwnProperty();
105 void selfDeletingBinding();
106 void extendedObjectPropertyLookup();
107 void extendedObjectPropertyLookup2();
109 void functionErrors();
110 void propertyAssignmentErrors();
111 void signalTriggeredBindings();
112 void listProperties();
113 void exceptionClearsOnReeval();
114 void exceptionSlotProducesWarning();
115 void exceptionBindingProducesWarning();
116 void compileInvalidBinding();
117 void transientErrors();
118 void shutdownErrors();
119 void compositePropertyType();
121 void undefinedResetsProperty();
122 void listToVariant();
123 void listAssignment();
124 void multiEngineObject();
125 void deletedObject();
126 void attachedPropertyScope();
127 void scriptConnect();
128 void scriptDisconnect();
130 void cppOwnershipReturnValue();
131 void ownershipCustomReturnValue();
132 void qlistqobjectMethods();
133 void strictlyEquals();
135 void numberAssignment();
136 void propertySplicing();
137 void signalWithUnknownTypes();
138 void signalWithJSValueInVariant_data();
139 void signalWithJSValueInVariant();
140 void signalWithJSValueInVariant_twoEngines_data();
141 void signalWithJSValueInVariant_twoEngines();
142 void signalWithQJSValue_data();
143 void signalWithQJSValue();
144 void moduleApi_data();
146 void importScripts_data();
147 void importScripts();
148 void scarceResources();
149 void scarceResources_data();
150 void scarceResources_other();
151 void propertyChangeSlots();
152 void propertyVar_data();
154 void propertyVarCpp();
155 void propertyVarOwnership();
156 void propertyVarImplicitOwnership();
157 void propertyVarReparent();
158 void propertyVarReparentNullContext();
159 void propertyVarCircular();
160 void propertyVarCircular2();
161 void propertyVarInheritance();
162 void propertyVarInheritance2();
163 void elementAssign();
164 void objectPassThroughSignals();
165 void objectConversion();
166 void booleanConversion();
167 void handleReferenceManagement();
169 void readonlyDeclaration();
170 void sequenceConversionRead();
171 void sequenceConversionWrite();
172 void sequenceConversionArray();
173 void sequenceConversionThreads();
174 void sequenceConversionBindings();
175 void sequenceConversionCopy();
176 void assignSequenceTypes();
182 void dynamicCreationCrash();
183 void dynamicCreationOwnership();
185 void nullObjectBinding();
186 void deletedEngine();
187 void libraryScriptAssert();
188 void variantsAssignedUndefined();
190 void qtcreatorbug_1289();
191 void noSpuriousWarningsAtShutdown();
192 void canAssignNullToQObject();
193 void functionAssignment_fromBinding();
194 void functionAssignment_fromJS();
195 void functionAssignment_fromJS_data();
196 void functionAssignmentfromJS_invalid();
203 void qobjectConnectionListExceptionHandling();
204 void nonscriptable();
208 void sharedAttachedObject();
210 void writeRemovesBinding();
211 void aliasBindingsAssignCorrectly();
212 void aliasBindingsOverrideTarget();
213 void aliasWritesOverrideBindings();
214 void aliasToCompositeElement();
217 void urlPropertyWithEncoding();
218 void urlListPropertyWithEncoding();
219 void dynamicString();
221 void signalHandlers();
222 void doubleEvaluate();
224 void nonNotifyable();
225 void deleteWhileBindingRunning();
226 void callQtInvokables();
227 void invokableObjectArg();
228 void invokableObjectRet();
231 void qtbug_22843_data();
233 void rewriteMultiLineStrings();
234 void revisionErrors();
237 void automaticSemicolon();
238 void unaryExpression();
239 void switchStatement();
240 void withStatement();
244 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
245 QDeclarativeEngine engine;
248 void tst_qdeclarativeecmascript::initTestCase()
250 QDeclarativeDataTest::initTestCase();
254 void tst_qdeclarativeecmascript::assignBasicTypes()
257 QDeclarativeComponent component(&engine, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("methods.3.qml"));
406 QObject *object = component.create();
407 QVERIFY(object != 0);
408 QCOMPARE(object->property("test").toInt(), 19);
413 QDeclarativeComponent component(&engine, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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 testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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, testFileUrl("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 = testFileUrl("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, testFileUrl("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, testFileUrl("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);
1225 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1226 QCoreApplication::processEvents();
1227 QVERIFY(createdQmlObject);
1228 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1229 if (createdQmlObject) {
1231 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1232 QCoreApplication::processEvents();
1235 QVERIFY(!createdQmlObject);
1237 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1238 QMetaObject::invokeMethod(object, "killMe");
1240 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1241 QCoreApplication::processEvents();
1246 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
1247 QObject *o = component.create();
1250 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1252 QMetaObject::invokeMethod(o, "create");
1254 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1256 QMetaObject::invokeMethod(o, "destroy");
1258 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1259 QCoreApplication::processEvents();
1261 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1268 tests that id.toString() works
1270 void tst_qdeclarativeecmascript::objectToString()
1272 QDeclarativeComponent component(&engine, testFileUrl("declarativeToString.qml"));
1273 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1274 QVERIFY(object != 0);
1275 QMetaObject::invokeMethod(object, "testToString");
1276 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1277 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1283 tests that id.hasOwnProperty() works
1285 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1287 QUrl url = testFileUrl("declarativeHasOwnProperty.qml");
1288 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1289 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1290 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1292 QDeclarativeComponent component(&engine, url);
1293 QObject *object = component.create();
1294 QVERIFY(object != 0);
1296 // test QObjects in QML
1297 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1298 QVERIFY(object->property("result").value<bool>() == true);
1299 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1300 QVERIFY(object->property("result").value<bool>() == false);
1302 // now test other types in QML
1303 QObject *child = object->findChild<QObject*>("typeObj");
1304 QVERIFY(child != 0);
1305 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1306 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1307 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1308 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1309 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1310 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1311 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1312 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1313 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1314 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1315 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1316 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1318 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1319 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1320 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1321 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1322 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1323 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1324 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1325 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1326 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1332 Tests bindings that indirectly cause their own deletion work.
1334 This test is best run under valgrind to ensure no invalid memory access occur.
1336 void tst_qdeclarativeecmascript::selfDeletingBinding()
1339 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
1340 QObject *object = component.create();
1341 QVERIFY(object != 0);
1342 object->setProperty("triggerDelete", true);
1347 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
1348 QObject *object = component.create();
1349 QVERIFY(object != 0);
1350 object->setProperty("triggerDelete", true);
1356 Test that extended object properties can be accessed.
1358 This test a regression where this used to crash. The issue was specificially
1359 for extended objects that did not include a synthesized meta object (so non-root
1360 and no synthesiszed properties).
1362 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1364 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
1365 QObject *object = component.create();
1366 QVERIFY(object != 0);
1371 Test that extended object properties can be accessed correctly.
1373 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
1375 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
1376 QObject *object = component.create();
1377 QVERIFY(object != 0);
1379 QVariant returnValue;
1380 QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
1381 QCOMPARE(returnValue.toInt(), 42);
1386 Test file/lineNumbers for binding/Script errors.
1388 void tst_qdeclarativeecmascript::scriptErrors()
1390 QDeclarativeComponent component(&engine, testFileUrl("scriptErrors.qml"));
1391 QString url = component.url().toString();
1393 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1394 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1395 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1396 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1397 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1398 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1399 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1400 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1402 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1403 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1404 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1405 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1406 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1407 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1408 QVERIFY(object != 0);
1410 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1411 emit object->basicSignal();
1413 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1414 emit object->anotherBasicSignal();
1416 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1417 emit object->thirdBasicSignal();
1423 Test file/lineNumbers for inline functions.
1425 void tst_qdeclarativeecmascript::functionErrors()
1427 QDeclarativeComponent component(&engine, testFileUrl("functionErrors.qml"));
1428 QString url = component.url().toString();
1430 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1432 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1434 QObject *object = component.create();
1435 QVERIFY(object != 0);
1438 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1439 QDeclarativeComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
1440 url = componentTwo.url().toString();
1441 object = componentTwo.create();
1442 QVERIFY(object != 0);
1444 QString srpname = object->property("srp_name").toString();
1446 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1447 + QLatin1String(" is not a function");
1448 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1449 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1454 Test various errors that can occur when assigning a property from script
1456 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1458 QDeclarativeComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
1460 QString url = component.url().toString();
1462 QObject *object = component.create();
1463 QVERIFY(object != 0);
1465 QCOMPARE(object->property("test1").toBool(), true);
1466 QCOMPARE(object->property("test2").toBool(), true);
1472 Test bindings still work when the reeval is triggered from within
1475 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1477 QDeclarativeComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
1478 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1479 QVERIFY(object != 0);
1481 QCOMPARE(object->property("base").toReal(), 50.);
1482 QCOMPARE(object->property("test1").toReal(), 50.);
1483 QCOMPARE(object->property("test2").toReal(), 50.);
1485 object->basicSignal();
1487 QCOMPARE(object->property("base").toReal(), 200.);
1488 QCOMPARE(object->property("test1").toReal(), 200.);
1489 QCOMPARE(object->property("test2").toReal(), 200.);
1491 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1493 QCOMPARE(object->property("base").toReal(), 400.);
1494 QCOMPARE(object->property("test1").toReal(), 400.);
1495 QCOMPARE(object->property("test2").toReal(), 400.);
1501 Test that list properties can be iterated from ECMAScript
1503 void tst_qdeclarativeecmascript::listProperties()
1505 QDeclarativeComponent component(&engine, testFileUrl("listProperties.qml"));
1506 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1507 QVERIFY(object != 0);
1509 QCOMPARE(object->property("test1").toInt(), 21);
1510 QCOMPARE(object->property("test2").toInt(), 2);
1511 QCOMPARE(object->property("test3").toBool(), true);
1512 QCOMPARE(object->property("test4").toBool(), true);
1517 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1519 QDeclarativeComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
1520 QString url = component.url().toString();
1522 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1524 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1525 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1526 QVERIFY(object != 0);
1528 QCOMPARE(object->property("test").toBool(), false);
1530 MyQmlObject object2;
1531 MyQmlObject object3;
1532 object2.setObjectProperty(&object3);
1533 object->setObjectProperty(&object2);
1535 QCOMPARE(object->property("test").toBool(), true);
1540 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1542 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
1543 QString url = component.url().toString();
1545 QString warning = component.url().toString() + ":6: Error: JS exception";
1547 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1548 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1549 QVERIFY(object != 0);
1553 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1555 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
1556 QString url = component.url().toString();
1558 QString warning = component.url().toString() + ":5: Error: JS exception";
1560 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1561 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1562 QVERIFY(object != 0);
1566 void tst_qdeclarativeecmascript::compileInvalidBinding()
1568 // QTBUG-23387: ensure that invalid bindings don't cause a crash.
1569 QDeclarativeComponent component(&engine, testFileUrl("v8bindingException.qml"));
1570 QString warning = component.url().toString() + ":16: SyntaxError: Unexpected token ILLEGAL";
1571 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1572 QObject *object = component.create();
1573 QVERIFY(object != 0);
1577 static int transientErrorsMsgCount = 0;
1578 static void transientErrorsMsgHandler(QtMsgType, const char *)
1580 ++transientErrorsMsgCount;
1583 // Check that transient binding errors are not displayed
1584 void tst_qdeclarativeecmascript::transientErrors()
1587 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
1589 transientErrorsMsgCount = 0;
1590 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1592 QObject *object = component.create();
1593 QVERIFY(object != 0);
1595 qInstallMsgHandler(old);
1597 QCOMPARE(transientErrorsMsgCount, 0);
1602 // One binding erroring multiple times, but then resolving
1604 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
1606 transientErrorsMsgCount = 0;
1607 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1609 QObject *object = component.create();
1610 QVERIFY(object != 0);
1612 qInstallMsgHandler(old);
1614 QCOMPARE(transientErrorsMsgCount, 0);
1620 // Check that errors during shutdown are minimized
1621 void tst_qdeclarativeecmascript::shutdownErrors()
1623 QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
1624 QObject *object = component.create();
1625 QVERIFY(object != 0);
1627 transientErrorsMsgCount = 0;
1628 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1632 qInstallMsgHandler(old);
1633 QCOMPARE(transientErrorsMsgCount, 0);
1636 void tst_qdeclarativeecmascript::compositePropertyType()
1638 QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
1640 QTest::ignoreMessage(QtDebugMsg, "hello world");
1641 QObject *object = qobject_cast<QObject *>(component.create());
1646 void tst_qdeclarativeecmascript::jsObject()
1648 QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
1649 QObject *object = component.create();
1650 QVERIFY(object != 0);
1652 QCOMPARE(object->property("test").toInt(), 92);
1657 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1660 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
1661 QObject *object = component.create();
1662 QVERIFY(object != 0);
1664 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1666 object->setProperty("setUndefined", true);
1668 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1670 object->setProperty("setUndefined", false);
1672 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1677 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
1678 QObject *object = component.create();
1679 QVERIFY(object != 0);
1681 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1683 QMetaObject::invokeMethod(object, "doReset");
1685 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1691 // Aliases to variant properties should work
1692 void tst_qdeclarativeecmascript::qtbug_22464()
1694 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
1695 QObject *object = component.create();
1696 QVERIFY(object != 0);
1698 QCOMPARE(object->property("test").toBool(), true);
1703 void tst_qdeclarativeecmascript::qtbug_21580()
1705 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
1707 QObject *object = component.create();
1708 QVERIFY(object != 0);
1710 QCOMPARE(object->property("test").toBool(), true);
1716 void tst_qdeclarativeecmascript::bug1()
1718 QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
1719 QObject *object = component.create();
1720 QVERIFY(object != 0);
1722 QCOMPARE(object->property("test").toInt(), 14);
1724 object->setProperty("a", 11);
1726 QCOMPARE(object->property("test").toInt(), 3);
1728 object->setProperty("b", true);
1730 QCOMPARE(object->property("test").toInt(), 9);
1735 void tst_qdeclarativeecmascript::bug2()
1737 QDeclarativeComponent component(&engine);
1738 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1740 QObject *object = component.create();
1741 QVERIFY(object != 0);
1746 // Don't crash in createObject when the component has errors.
1747 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1749 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1750 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1751 QVERIFY(object != 0);
1753 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1754 QMetaObject::invokeMethod(object, "dontCrash");
1755 QObject *created = object->objectProperty();
1756 QVERIFY(created == 0);
1761 // ownership transferred to JS, ensure that GC runs the dtor
1762 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1765 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1767 // allow the engine to go out of scope too.
1769 QDeclarativeEngine dcoEngine;
1770 QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
1771 QObject *object = component.create();
1772 QVERIFY(object != 0);
1773 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1774 QVERIFY(mdcdo != 0);
1775 mdcdo->setDtorCount(&dtorCount);
1777 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1778 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1780 // we do this once manually, but it should be done automatically
1781 // when the engine goes out of scope (since it should gc in dtor)
1782 QMetaObject::invokeMethod(object, "performGc");
1785 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1786 QCoreApplication::processEvents();
1792 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1793 QCoreApplication::processEvents();
1794 QCOMPARE(dtorCount, expectedDtorCount);
1797 void tst_qdeclarativeecmascript::regExpBug()
1801 QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
1802 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1803 QVERIFY(object != 0);
1804 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1810 QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
1811 QDeclarativeComponent component(&engine, testFileUrl("regExp.2.qml"));
1812 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1813 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1815 QCOMPARE(component.errorString(), err);
1819 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1821 QString functionSource = QLatin1String("(function(object) { return ") +
1822 QLatin1String(source) + QLatin1String(" })");
1824 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1827 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1828 if (function.IsEmpty())
1830 v8::Handle<v8::Value> args[] = { o };
1831 function->Call(engine->global(), 1, args);
1832 return tc.HasCaught();
1835 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1836 const char *source, v8::Handle<v8::Value> result)
1838 QString functionSource = QLatin1String("(function(object) { return ") +
1839 QLatin1String(source) + QLatin1String(" })");
1841 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1844 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1845 if (function.IsEmpty())
1847 v8::Handle<v8::Value> args[] = { o };
1849 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1854 return value->StrictEquals(result);
1857 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1860 QString functionSource = QLatin1String("(function(object) { return ") +
1861 QLatin1String(source) + QLatin1String(" })");
1863 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1865 return v8::Handle<v8::Value>();
1866 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1867 if (function.IsEmpty())
1868 return v8::Handle<v8::Value>();
1869 v8::Handle<v8::Value> args[] = { o };
1871 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1874 return v8::Handle<v8::Value>();
1878 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1879 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1880 #define EVALUATE(source) evaluate(engine, object, source)
1882 void tst_qdeclarativeecmascript::callQtInvokables()
1884 MyInvokableObject o;
1886 QDeclarativeEngine qmlengine;
1887 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1889 QV8Engine *engine = ep->v8engine();
1891 v8::HandleScope handle_scope;
1892 v8::Context::Scope scope(engine->context());
1894 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1896 // Non-existent methods
1898 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1899 QCOMPARE(o.error(), false);
1900 QCOMPARE(o.invoked(), -1);
1901 QCOMPARE(o.actuals().count(), 0);
1904 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1905 QCOMPARE(o.error(), false);
1906 QCOMPARE(o.invoked(), -1);
1907 QCOMPARE(o.actuals().count(), 0);
1909 // Insufficient arguments
1911 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1912 QCOMPARE(o.error(), false);
1913 QCOMPARE(o.invoked(), -1);
1914 QCOMPARE(o.actuals().count(), 0);
1917 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1918 QCOMPARE(o.error(), false);
1919 QCOMPARE(o.invoked(), -1);
1920 QCOMPARE(o.actuals().count(), 0);
1922 // Excessive arguments
1924 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1925 QCOMPARE(o.error(), false);
1926 QCOMPARE(o.invoked(), 8);
1927 QCOMPARE(o.actuals().count(), 1);
1928 QCOMPARE(o.actuals().at(0), QVariant(10));
1931 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1932 QCOMPARE(o.error(), false);
1933 QCOMPARE(o.invoked(), 9);
1934 QCOMPARE(o.actuals().count(), 2);
1935 QCOMPARE(o.actuals().at(0), QVariant(10));
1936 QCOMPARE(o.actuals().at(1), QVariant(11));
1938 // Test return types
1940 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1941 QCOMPARE(o.error(), false);
1942 QCOMPARE(o.invoked(), 0);
1943 QCOMPARE(o.actuals().count(), 0);
1946 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1947 QCOMPARE(o.error(), false);
1948 QCOMPARE(o.invoked(), 1);
1949 QCOMPARE(o.actuals().count(), 0);
1952 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1953 QCOMPARE(o.error(), false);
1954 QCOMPARE(o.invoked(), 2);
1955 QCOMPARE(o.actuals().count(), 0);
1959 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1960 QVERIFY(!ret.IsEmpty());
1961 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1962 QCOMPARE(o.error(), false);
1963 QCOMPARE(o.invoked(), 3);
1964 QCOMPARE(o.actuals().count(), 0);
1969 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1970 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1971 QCOMPARE(o.error(), false);
1972 QCOMPARE(o.invoked(), 4);
1973 QCOMPARE(o.actuals().count(), 0);
1977 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1978 QCOMPARE(o.error(), false);
1979 QCOMPARE(o.invoked(), 5);
1980 QCOMPARE(o.actuals().count(), 0);
1984 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1985 QVERIFY(ret->IsString());
1986 QCOMPARE(engine->toString(ret), QString("Hello world"));
1987 QCOMPARE(o.error(), false);
1988 QCOMPARE(o.invoked(), 6);
1989 QCOMPARE(o.actuals().count(), 0);
1993 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1994 QCOMPARE(o.error(), false);
1995 QCOMPARE(o.invoked(), 7);
1996 QCOMPARE(o.actuals().count(), 0);
2000 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
2001 QCOMPARE(o.error(), false);
2002 QCOMPARE(o.invoked(), 8);
2003 QCOMPARE(o.actuals().count(), 1);
2004 QCOMPARE(o.actuals().at(0), QVariant(94));
2007 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
2008 QCOMPARE(o.error(), false);
2009 QCOMPARE(o.invoked(), 8);
2010 QCOMPARE(o.actuals().count(), 1);
2011 QCOMPARE(o.actuals().at(0), QVariant(94));
2014 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
2015 QCOMPARE(o.error(), false);
2016 QCOMPARE(o.invoked(), 8);
2017 QCOMPARE(o.actuals().count(), 1);
2018 QCOMPARE(o.actuals().at(0), QVariant(0));
2021 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
2022 QCOMPARE(o.error(), false);
2023 QCOMPARE(o.invoked(), 8);
2024 QCOMPARE(o.actuals().count(), 1);
2025 QCOMPARE(o.actuals().at(0), QVariant(0));
2028 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
2029 QCOMPARE(o.error(), false);
2030 QCOMPARE(o.invoked(), 8);
2031 QCOMPARE(o.actuals().count(), 1);
2032 QCOMPARE(o.actuals().at(0), QVariant(0));
2035 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2036 QCOMPARE(o.error(), false);
2037 QCOMPARE(o.invoked(), 8);
2038 QCOMPARE(o.actuals().count(), 1);
2039 QCOMPARE(o.actuals().at(0), QVariant(0));
2042 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2043 QCOMPARE(o.error(), false);
2044 QCOMPARE(o.invoked(), 9);
2045 QCOMPARE(o.actuals().count(), 2);
2046 QCOMPARE(o.actuals().at(0), QVariant(122));
2047 QCOMPARE(o.actuals().at(1), QVariant(9));
2050 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2051 QCOMPARE(o.error(), false);
2052 QCOMPARE(o.invoked(), 10);
2053 QCOMPARE(o.actuals().count(), 1);
2054 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2057 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2058 QCOMPARE(o.error(), false);
2059 QCOMPARE(o.invoked(), 10);
2060 QCOMPARE(o.actuals().count(), 1);
2061 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2064 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2065 QCOMPARE(o.error(), false);
2066 QCOMPARE(o.invoked(), 10);
2067 QCOMPARE(o.actuals().count(), 1);
2068 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2071 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2072 QCOMPARE(o.error(), false);
2073 QCOMPARE(o.invoked(), 10);
2074 QCOMPARE(o.actuals().count(), 1);
2075 QCOMPARE(o.actuals().at(0), QVariant(0));
2078 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2079 QCOMPARE(o.error(), false);
2080 QCOMPARE(o.invoked(), 10);
2081 QCOMPARE(o.actuals().count(), 1);
2082 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2085 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2086 QCOMPARE(o.error(), false);
2087 QCOMPARE(o.invoked(), 10);
2088 QCOMPARE(o.actuals().count(), 1);
2089 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2092 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2093 QCOMPARE(o.error(), false);
2094 QCOMPARE(o.invoked(), 11);
2095 QCOMPARE(o.actuals().count(), 1);
2096 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2099 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2100 QCOMPARE(o.error(), false);
2101 QCOMPARE(o.invoked(), 11);
2102 QCOMPARE(o.actuals().count(), 1);
2103 QCOMPARE(o.actuals().at(0), QVariant("19"));
2107 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2108 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2109 QCOMPARE(o.error(), false);
2110 QCOMPARE(o.invoked(), 11);
2111 QCOMPARE(o.actuals().count(), 1);
2112 QCOMPARE(o.actuals().at(0), QVariant(expected));
2116 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2117 QCOMPARE(o.error(), false);
2118 QCOMPARE(o.invoked(), 11);
2119 QCOMPARE(o.actuals().count(), 1);
2120 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2123 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2124 QCOMPARE(o.error(), false);
2125 QCOMPARE(o.invoked(), 11);
2126 QCOMPARE(o.actuals().count(), 1);
2127 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2130 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2131 QCOMPARE(o.error(), false);
2132 QCOMPARE(o.invoked(), 12);
2133 QCOMPARE(o.actuals().count(), 1);
2134 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2137 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2138 QCOMPARE(o.error(), false);
2139 QCOMPARE(o.invoked(), 12);
2140 QCOMPARE(o.actuals().count(), 1);
2141 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2144 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2145 QCOMPARE(o.error(), false);
2146 QCOMPARE(o.invoked(), 12);
2147 QCOMPARE(o.actuals().count(), 1);
2148 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2151 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2152 QCOMPARE(o.error(), false);
2153 QCOMPARE(o.invoked(), 12);
2154 QCOMPARE(o.actuals().count(), 1);
2155 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2158 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2159 QCOMPARE(o.error(), false);
2160 QCOMPARE(o.invoked(), 12);
2161 QCOMPARE(o.actuals().count(), 1);
2162 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2165 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2166 QCOMPARE(o.error(), false);
2167 QCOMPARE(o.invoked(), 12);
2168 QCOMPARE(o.actuals().count(), 1);
2169 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2172 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2173 QCOMPARE(o.error(), false);
2174 QCOMPARE(o.invoked(), 13);
2175 QCOMPARE(o.actuals().count(), 1);
2176 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2179 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2180 QCOMPARE(o.error(), false);
2181 QCOMPARE(o.invoked(), 13);
2182 QCOMPARE(o.actuals().count(), 1);
2183 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2186 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2187 QCOMPARE(o.error(), false);
2188 QCOMPARE(o.invoked(), 13);
2189 QCOMPARE(o.actuals().count(), 1);
2190 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2193 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2194 QCOMPARE(o.error(), false);
2195 QCOMPARE(o.invoked(), 13);
2196 QCOMPARE(o.actuals().count(), 1);
2197 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2200 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2201 QCOMPARE(o.error(), false);
2202 QCOMPARE(o.invoked(), 13);
2203 QCOMPARE(o.actuals().count(), 1);
2204 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2207 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2208 QCOMPARE(o.error(), false);
2209 QCOMPARE(o.invoked(), 14);
2210 QCOMPARE(o.actuals().count(), 1);
2211 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2214 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2215 QCOMPARE(o.error(), false);
2216 QCOMPARE(o.invoked(), 14);
2217 QCOMPARE(o.actuals().count(), 1);
2218 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2221 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2222 QCOMPARE(o.error(), false);
2223 QCOMPARE(o.invoked(), 14);
2224 QCOMPARE(o.actuals().count(), 1);
2225 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2228 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2229 QCOMPARE(o.error(), false);
2230 QCOMPARE(o.invoked(), 14);
2231 QCOMPARE(o.actuals().count(), 1);
2232 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2235 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2236 QCOMPARE(o.error(), false);
2237 QCOMPARE(o.invoked(), 15);
2238 QCOMPARE(o.actuals().count(), 2);
2239 QCOMPARE(o.actuals().at(0), QVariant(4));
2240 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2243 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2244 QCOMPARE(o.error(), false);
2245 QCOMPARE(o.invoked(), 15);
2246 QCOMPARE(o.actuals().count(), 2);
2247 QCOMPARE(o.actuals().at(0), QVariant(8));
2248 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2251 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2252 QCOMPARE(o.error(), false);
2253 QCOMPARE(o.invoked(), 15);
2254 QCOMPARE(o.actuals().count(), 2);
2255 QCOMPARE(o.actuals().at(0), QVariant(3));
2256 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2259 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2260 QCOMPARE(o.error(), false);
2261 QCOMPARE(o.invoked(), 15);
2262 QCOMPARE(o.actuals().count(), 2);
2263 QCOMPARE(o.actuals().at(0), QVariant(44));
2264 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2267 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2268 QCOMPARE(o.error(), false);
2269 QCOMPARE(o.invoked(), -1);
2270 QCOMPARE(o.actuals().count(), 0);
2273 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2274 QCOMPARE(o.error(), false);
2275 QCOMPARE(o.invoked(), 16);
2276 QCOMPARE(o.actuals().count(), 1);
2277 QCOMPARE(o.actuals().at(0), QVariant(10));
2280 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2281 QCOMPARE(o.error(), false);
2282 QCOMPARE(o.invoked(), 17);
2283 QCOMPARE(o.actuals().count(), 2);
2284 QCOMPARE(o.actuals().at(0), QVariant(10));
2285 QCOMPARE(o.actuals().at(1), QVariant(11));
2288 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2289 QCOMPARE(o.error(), false);
2290 QCOMPARE(o.invoked(), 18);
2291 QCOMPARE(o.actuals().count(), 1);
2292 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2295 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2296 QCOMPARE(o.error(), false);
2297 QCOMPARE(o.invoked(), 19);
2298 QCOMPARE(o.actuals().count(), 1);
2299 QCOMPARE(o.actuals().at(0), QVariant(9));
2302 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2303 QCOMPARE(o.error(), false);
2304 QCOMPARE(o.invoked(), 20);
2305 QCOMPARE(o.actuals().count(), 2);
2306 QCOMPARE(o.actuals().at(0), QVariant(10));
2307 QCOMPARE(o.actuals().at(1), QVariant(19));
2310 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2311 QCOMPARE(o.error(), false);
2312 QCOMPARE(o.invoked(), 20);
2313 QCOMPARE(o.actuals().count(), 2);
2314 QCOMPARE(o.actuals().at(0), QVariant(10));
2315 QCOMPARE(o.actuals().at(1), QVariant(13));
2318 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2319 QCOMPARE(o.error(), false);
2320 QCOMPARE(o.invoked(), -3);
2321 QCOMPARE(o.actuals().count(), 1);
2322 QCOMPARE(o.actuals().at(0), QVariant(9));
2325 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2326 QCOMPARE(o.error(), false);
2327 QCOMPARE(o.invoked(), 21);
2328 QCOMPARE(o.actuals().count(), 2);
2329 QCOMPARE(o.actuals().at(0), QVariant(9));
2330 QCOMPARE(o.actuals().at(1), QVariant());
2333 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2334 QCOMPARE(o.error(), false);
2335 QCOMPARE(o.invoked(), 21);
2336 QCOMPARE(o.actuals().count(), 2);
2337 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2338 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2341 // QTBUG-13047 (check that you can pass registered object types as args)
2342 void tst_qdeclarativeecmascript::invokableObjectArg()
2344 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
2346 QObject *o = component.create();
2348 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2350 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2355 // QTBUG-13047 (check that you can return registered object types from methods)
2356 void tst_qdeclarativeecmascript::invokableObjectRet()
2358 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
2360 QObject *o = component.create();
2362 QCOMPARE(o->property("test").toBool(), true);
2367 void tst_qdeclarativeecmascript::listToVariant()
2369 QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
2371 MyQmlContainer container;
2373 QDeclarativeContext context(engine.rootContext());
2374 context.setContextObject(&container);
2376 QObject *object = component.create(&context);
2377 QVERIFY(object != 0);
2379 QVariant v = object->property("test");
2380 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2381 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2387 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2388 void tst_qdeclarativeecmascript::listAssignment()
2390 QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
2391 QObject *obj = component.create();
2392 QCOMPARE(obj->property("list1length").toInt(), 2);
2393 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2394 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2395 QCOMPARE(list1.count(&list1), list2.count(&list2));
2396 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2397 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2402 void tst_qdeclarativeecmascript::multiEngineObject()
2405 obj.setStringProperty("Howdy planet");
2407 QDeclarativeEngine e1;
2408 e1.rootContext()->setContextProperty("thing", &obj);
2409 QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
2411 QDeclarativeEngine e2;
2412 e2.rootContext()->setContextProperty("thing", &obj);
2413 QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
2415 QObject *o1 = c1.create();
2416 QObject *o2 = c2.create();
2418 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2419 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2425 // Test that references to QObjects are cleanup when the object is destroyed
2426 void tst_qdeclarativeecmascript::deletedObject()
2428 QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
2430 QObject *object = component.create();
2432 QCOMPARE(object->property("test1").toBool(), true);
2433 QCOMPARE(object->property("test2").toBool(), true);
2434 QCOMPARE(object->property("test3").toBool(), true);
2435 QCOMPARE(object->property("test4").toBool(), true);
2440 void tst_qdeclarativeecmascript::attachedPropertyScope()
2442 QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
2444 QObject *object = component.create();
2445 QVERIFY(object != 0);
2447 MyQmlAttachedObject *attached =
2448 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2449 QVERIFY(attached != 0);
2451 QCOMPARE(object->property("value2").toInt(), 0);
2453 attached->emitMySignal();
2455 QCOMPARE(object->property("value2").toInt(), 9);
2460 void tst_qdeclarativeecmascript::scriptConnect()
2463 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
2465 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2466 QVERIFY(object != 0);
2468 QCOMPARE(object->property("test").toBool(), false);
2469 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2470 QCOMPARE(object->property("test").toBool(), true);
2476 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
2478 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2479 QVERIFY(object != 0);
2481 QCOMPARE(object->property("test").toBool(), false);
2482 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2483 QCOMPARE(object->property("test").toBool(), true);
2489 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
2491 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2492 QVERIFY(object != 0);
2494 QCOMPARE(object->property("test").toBool(), false);
2495 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2496 QCOMPARE(object->property("test").toBool(), true);
2502 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
2504 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2505 QVERIFY(object != 0);
2507 QCOMPARE(object->methodCalled(), false);
2508 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2509 QCOMPARE(object->methodCalled(), true);
2515 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
2517 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2518 QVERIFY(object != 0);
2520 QCOMPARE(object->methodCalled(), false);
2521 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2522 QCOMPARE(object->methodCalled(), true);
2528 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
2530 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2531 QVERIFY(object != 0);
2533 QCOMPARE(object->property("test").toInt(), 0);
2534 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2535 QCOMPARE(object->property("test").toInt(), 2);
2541 void tst_qdeclarativeecmascript::scriptDisconnect()
2544 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
2546 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2547 QVERIFY(object != 0);
2549 QCOMPARE(object->property("test").toInt(), 0);
2550 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2551 QCOMPARE(object->property("test").toInt(), 1);
2552 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2553 QCOMPARE(object->property("test").toInt(), 2);
2554 emit object->basicSignal();
2555 QCOMPARE(object->property("test").toInt(), 2);
2556 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2557 QCOMPARE(object->property("test").toInt(), 2);
2563 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
2565 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2566 QVERIFY(object != 0);
2568 QCOMPARE(object->property("test").toInt(), 0);
2569 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2570 QCOMPARE(object->property("test").toInt(), 1);
2571 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2572 QCOMPARE(object->property("test").toInt(), 2);
2573 emit object->basicSignal();
2574 QCOMPARE(object->property("test").toInt(), 2);
2575 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2576 QCOMPARE(object->property("test").toInt(), 2);
2582 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
2584 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2585 QVERIFY(object != 0);
2587 QCOMPARE(object->property("test").toInt(), 0);
2588 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2589 QCOMPARE(object->property("test").toInt(), 1);
2590 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2591 QCOMPARE(object->property("test").toInt(), 2);
2592 emit object->basicSignal();
2593 QCOMPARE(object->property("test").toInt(), 2);
2594 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2595 QCOMPARE(object->property("test").toInt(), 3);
2600 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
2602 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2603 QVERIFY(object != 0);
2605 QCOMPARE(object->property("test").toInt(), 0);
2606 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2607 QCOMPARE(object->property("test").toInt(), 1);
2608 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2609 QCOMPARE(object->property("test").toInt(), 2);
2610 emit object->basicSignal();
2611 QCOMPARE(object->property("test").toInt(), 2);
2612 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2613 QCOMPARE(object->property("test").toInt(), 3);
2619 class OwnershipObject : public QObject
2623 OwnershipObject() { object = new QObject; }
2625 QPointer<QObject> object;
2628 QObject *getObject() { return object; }
2631 void tst_qdeclarativeecmascript::ownership()
2633 OwnershipObject own;
2634 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2635 context->setContextObject(&own);
2638 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2640 QVERIFY(own.object != 0);
2642 QObject *object = component.create(context);
2644 engine.collectGarbage();
2646 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2647 QCoreApplication::processEvents();
2649 QVERIFY(own.object == 0);
2654 own.object = new QObject(&own);
2657 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2659 QVERIFY(own.object != 0);
2661 QObject *object = component.create(context);
2663 engine.collectGarbage();
2665 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2666 QCoreApplication::processEvents();
2668 QVERIFY(own.object != 0);
2676 class CppOwnershipReturnValue : public QObject
2680 CppOwnershipReturnValue() : value(0) {}
2681 ~CppOwnershipReturnValue() { delete value; }
2683 Q_INVOKABLE QObject *create() {
2684 value = new QObject;
2685 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2689 Q_INVOKABLE MyQmlObject *createQmlObject() {
2690 MyQmlObject *rv = new MyQmlObject;
2695 QPointer<QObject> value;
2699 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2700 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2702 CppOwnershipReturnValue source;
2705 QDeclarativeEngine engine;
2706 engine.rootContext()->setContextProperty("source", &source);
2708 QVERIFY(source.value == 0);
2710 QDeclarativeComponent component(&engine);
2711 component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2713 QObject *object = component.create();
2715 QVERIFY(object != 0);
2716 QVERIFY(source.value != 0);
2721 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2722 QCoreApplication::processEvents();
2724 QVERIFY(source.value != 0);
2728 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2730 CppOwnershipReturnValue source;
2733 QDeclarativeEngine engine;
2734 engine.rootContext()->setContextProperty("source", &source);
2736 QVERIFY(source.value == 0);
2738 QDeclarativeComponent component(&engine);
2739 component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2741 QObject *object = component.create();
2743 QVERIFY(object != 0);
2744 QVERIFY(source.value != 0);
2749 engine.collectGarbage();
2750 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2751 QCoreApplication::processEvents();
2753 QVERIFY(source.value == 0);
2756 class QListQObjectMethodsObject : public QObject
2760 QListQObjectMethodsObject() {
2761 m_objects.append(new MyQmlObject());
2762 m_objects.append(new MyQmlObject());
2765 ~QListQObjectMethodsObject() {
2766 qDeleteAll(m_objects);
2770 QList<QObject *> getObjects() { return m_objects; }
2773 QList<QObject *> m_objects;
2776 // Tests that returning a QList<QObject*> from a method works
2777 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2779 QListQObjectMethodsObject obj;
2780 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2781 context->setContextObject(&obj);
2783 QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
2785 QObject *object = component.create(context);
2787 QCOMPARE(object->property("test").toInt(), 2);
2788 QCOMPARE(object->property("test2").toBool(), true);
2795 void tst_qdeclarativeecmascript::strictlyEquals()
2797 QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
2799 QObject *object = component.create();
2800 QVERIFY(object != 0);
2802 QCOMPARE(object->property("test1").toBool(), true);
2803 QCOMPARE(object->property("test2").toBool(), true);
2804 QCOMPARE(object->property("test3").toBool(), true);
2805 QCOMPARE(object->property("test4").toBool(), true);
2806 QCOMPARE(object->property("test5").toBool(), true);
2807 QCOMPARE(object->property("test6").toBool(), true);
2808 QCOMPARE(object->property("test7").toBool(), true);
2809 QCOMPARE(object->property("test8").toBool(), true);
2814 void tst_qdeclarativeecmascript::compiled()
2816 QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
2818 QObject *object = component.create();
2819 QVERIFY(object != 0);
2821 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2822 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2823 QCOMPARE(object->property("test3").toBool(), true);
2824 QCOMPARE(object->property("test4").toBool(), false);
2825 QCOMPARE(object->property("test5").toBool(), false);
2826 QCOMPARE(object->property("test6").toBool(), true);
2828 QCOMPARE(object->property("test7").toInt(), 185);
2829 QCOMPARE(object->property("test8").toInt(), 167);
2830 QCOMPARE(object->property("test9").toBool(), true);
2831 QCOMPARE(object->property("test10").toBool(), false);
2832 QCOMPARE(object->property("test11").toBool(), false);
2833 QCOMPARE(object->property("test12").toBool(), true);
2835 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2836 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2837 QCOMPARE(object->property("test15").toBool(), false);
2838 QCOMPARE(object->property("test16").toBool(), true);
2840 QCOMPARE(object->property("test17").toInt(), 5);
2841 QCOMPARE(object->property("test18").toReal(), qreal(176));
2842 QCOMPARE(object->property("test19").toInt(), 7);
2843 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2844 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2845 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2846 QCOMPARE(object->property("test23").toBool(), true);
2847 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2848 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2853 // Test that numbers assigned in bindings as strings work consistently
2854 void tst_qdeclarativeecmascript::numberAssignment()
2856 QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
2858 QObject *object = component.create();
2859 QVERIFY(object != 0);
2861 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2862 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2863 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2864 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2865 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2867 QCOMPARE(object->property("test5"), QVariant((int)7));
2868 QCOMPARE(object->property("test6"), QVariant((int)7));
2869 QCOMPARE(object->property("test7"), QVariant((int)6));
2870 QCOMPARE(object->property("test8"), QVariant((int)6));
2872 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2873 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2874 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2875 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2880 void tst_qdeclarativeecmascript::propertySplicing()
2882 QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
2884 QObject *object = component.create();
2885 QVERIFY(object != 0);
2887 QCOMPARE(object->property("test").toBool(), true);
2893 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2895 QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
2897 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2898 QVERIFY(object != 0);
2900 MyQmlObject::MyType type;
2901 type.value = 0x8971123;
2902 emit object->signalWithUnknownType(type);
2904 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2906 QCOMPARE(result.value, type.value);
2912 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2914 QTest::addColumn<QString>("expression");
2915 QTest::addColumn<QString>("compare");
2917 QString compareStrict("(function(a, b) { return a === b; })");
2918 QTest::newRow("true") << "true" << compareStrict;
2919 QTest::newRow("undefined") << "undefined" << compareStrict;
2920 QTest::newRow("null") << "null" << compareStrict;
2921 QTest::newRow("123") << "123" << compareStrict;
2922 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2924 QString comparePropertiesStrict(
2926 " if (typeof b != 'object')"
2928 " var props = Object.getOwnPropertyNames(b);"
2929 " for (var i = 0; i < props.length; ++i) {"
2930 " var p = props[i];"
2931 " return arguments.callee(a[p], b[p]);"
2934 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2935 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2938 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2940 QFETCH(QString, expression);
2941 QFETCH(QString, compare);
2943 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2944 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2945 QVERIFY(object != 0);
2947 QJSValue value = engine.evaluate(expression);
2948 QVERIFY(!engine.hasUncaughtException());
2949 object->setProperty("expression", expression);
2950 object->setProperty("compare", compare);
2951 object->setProperty("pass", false);
2953 emit object->signalWithVariant(QVariant::fromValue(value));
2954 QVERIFY(object->property("pass").toBool());
2957 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2959 signalWithJSValueInVariant_data();
2962 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2964 QFETCH(QString, expression);
2965 QFETCH(QString, compare);
2967 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2968 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2969 QVERIFY(object != 0);
2972 QJSValue value = engine2.evaluate(expression);
2973 QVERIFY(!engine2.hasUncaughtException());
2974 object->setProperty("expression", expression);
2975 object->setProperty("compare", compare);
2976 object->setProperty("pass", false);
2978 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2979 emit object->signalWithVariant(QVariant::fromValue(value));
2980 QVERIFY(!object->property("pass").toBool());
2983 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2985 signalWithJSValueInVariant_data();
2988 void tst_qdeclarativeecmascript::signalWithQJSValue()
2990 QFETCH(QString, expression);
2991 QFETCH(QString, compare);
2993 QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
2994 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2995 QVERIFY(object != 0);
2997 QJSValue value = engine.evaluate(expression);
2998 QVERIFY(!engine.hasUncaughtException());
2999 object->setProperty("expression", expression);
3000 object->setProperty("compare", compare);
3001 object->setProperty("pass", false);
3003 emit object->signalWithQJSValue(value);
3005 QVERIFY(object->property("pass").toBool());
3006 QVERIFY(object->qjsvalue().strictlyEquals(value));
3009 void tst_qdeclarativeecmascript::moduleApi_data()
3011 QTest::addColumn<QUrl>("testfile");
3012 QTest::addColumn<QString>("errorMessage");
3013 QTest::addColumn<QStringList>("warningMessages");
3014 QTest::addColumn<QStringList>("readProperties");
3015 QTest::addColumn<QVariantList>("readExpectedValues");
3016 QTest::addColumn<QStringList>("writeProperties");
3017 QTest::addColumn<QVariantList>("writeValues");
3018 QTest::addColumn<QStringList>("readBackProperties");
3019 QTest::addColumn<QVariantList>("readBackExpectedValues");
3021 QTest::newRow("qobject, register + read + method")
3022 << testFileUrl("moduleapi/qobjectModuleApi.qml")
3025 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
3026 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
3027 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
3033 QTest::newRow("script, register + read")
3034 << testFileUrl("moduleapi/scriptModuleApi.qml")
3037 << (QStringList() << "scriptTest")
3038 << (QVariantList() << 13)
3044 QTest::newRow("qobject, caching + read")
3045 << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
3048 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3049 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3055 QTest::newRow("script, caching + read")
3056 << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
3059 << (QStringList() << "scriptTest")
3060 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3066 QTest::newRow("qobject, writing + readonly constraints")
3067 << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
3069 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3070 << (QStringList() << "readOnlyProperty" << "writableProperty")
3071 << (QVariantList() << 20 << 50)
3072 << (QStringList() << "firstProperty" << "writableProperty")
3073 << (QVariantList() << 30 << 30)
3074 << (QStringList() << "readOnlyProperty" << "writableProperty")
3075 << (QVariantList() << 20 << 30);
3077 QTest::newRow("script, writing + readonly constraints")
3078 << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
3080 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3081 << (QStringList() << "readBack" << "unchanged")
3082 << (QVariantList() << 13 << 42)
3083 << (QStringList() << "firstProperty" << "secondProperty")
3084 << (QVariantList() << 30 << 30)
3085 << (QStringList() << "readBack" << "unchanged")
3086 << (QVariantList() << 30 << 42);
3088 QTest::newRow("qobject module API enum values in JS")
3089 << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
3092 << (QStringList() << "enumValue" << "enumMethod")
3093 << (QVariantList() << 42 << 30)
3099 QTest::newRow("qobject, invalid major version fail")
3100 << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
3101 << QString("QDeclarativeComponent: Component is not ready")
3110 QTest::newRow("qobject, invalid minor version fail")
3111 << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
3112 << QString("QDeclarativeComponent: Component is not ready")
3122 void tst_qdeclarativeecmascript::moduleApi()
3124 QFETCH(QUrl, testfile);
3125 QFETCH(QString, errorMessage);
3126 QFETCH(QStringList, warningMessages);
3127 QFETCH(QStringList, readProperties);
3128 QFETCH(QVariantList, readExpectedValues);
3129 QFETCH(QStringList, writeProperties);
3130 QFETCH(QVariantList, writeValues);
3131 QFETCH(QStringList, readBackProperties);
3132 QFETCH(QVariantList, readBackExpectedValues);
3134 QDeclarativeComponent component(&engine, testfile);
3136 if (!errorMessage.isEmpty())
3137 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3139 if (warningMessages.size())
3140 foreach (const QString &warning, warningMessages)
3141 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3143 QObject *object = component.create();
3144 if (!errorMessage.isEmpty()) {
3145 QVERIFY(object == 0);
3147 QVERIFY(object != 0);
3148 for (int i = 0; i < readProperties.size(); ++i)
3149 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3150 for (int i = 0; i < writeProperties.size(); ++i)
3151 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3152 for (int i = 0; i < readBackProperties.size(); ++i)
3153 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3158 void tst_qdeclarativeecmascript::importScripts_data()
3160 QTest::addColumn<QUrl>("testfile");
3161 QTest::addColumn<QString>("errorMessage");
3162 QTest::addColumn<QStringList>("warningMessages");
3163 QTest::addColumn<QStringList>("propertyNames");
3164 QTest::addColumn<QVariantList>("propertyValues");
3166 QTest::newRow("basic functionality")
3167 << testFileUrl("jsimport/testImport.qml")
3170 << (QStringList() << QLatin1String("importedScriptStringValue")
3171 << QLatin1String("importedScriptFunctionValue")
3172 << QLatin1String("importedModuleAttachedPropertyValue")
3173 << QLatin1String("importedModuleEnumValue"))
3174 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3179 QTest::newRow("import scoping")
3180 << testFileUrl("jsimport/testImportScoping.qml")
3183 << (QStringList() << QLatin1String("componentError"))
3184 << (QVariantList() << QVariant(5));
3186 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3187 << testFileUrl("jsimportfail/failOne.qml")
3189 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3190 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3191 << (QVariantList() << QVariant(QString()));
3193 QTest::newRow("javascript imports in an import should be private to the import scope")
3194 << testFileUrl("jsimportfail/failTwo.qml")
3196 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3197 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3198 << (QVariantList() << QVariant(QString()));
3200 QTest::newRow("module imports in an import should be private to the import scope")
3201 << testFileUrl("jsimportfail/failThree.qml")
3203 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3204 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3205 << (QVariantList() << QVariant(false));
3207 QTest::newRow("typenames in an import should be private to the import scope")
3208 << testFileUrl("jsimportfail/failFour.qml")
3210 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3211 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3212 << (QVariantList() << QVariant(0));
3214 QTest::newRow("import with imports has it's own activation scope")
3215 << testFileUrl("jsimportfail/failFive.qml")
3217 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component")))
3218 << (QStringList() << QLatin1String("componentError"))
3219 << (QVariantList() << QVariant(0));
3221 QTest::newRow("import pragma library script")
3222 << testFileUrl("jsimport/testImportPragmaLibrary.qml")
3225 << (QStringList() << QLatin1String("testValue"))
3226 << (QVariantList() << QVariant(31));
3228 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3229 << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
3231 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3232 << (QStringList() << QLatin1String("testValue"))
3233 << (QVariantList() << QVariant(0));
3235 QTest::newRow("import pragma library script which has an import")
3236 << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
3239 << (QStringList() << QLatin1String("testValue"))
3240 << (QVariantList() << QVariant(55));
3242 QTest::newRow("import pragma library script which has a pragma library import")
3243 << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3246 << (QStringList() << QLatin1String("testValue"))
3247 << (QVariantList() << QVariant(18));
3250 void tst_qdeclarativeecmascript::importScripts()
3252 QFETCH(QUrl, testfile);
3253 QFETCH(QString, errorMessage);
3254 QFETCH(QStringList, warningMessages);
3255 QFETCH(QStringList, propertyNames);
3256 QFETCH(QVariantList, propertyValues);
3258 QDeclarativeComponent component(&engine, testfile);
3260 if (!errorMessage.isEmpty())
3261 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3263 if (warningMessages.size())
3264 foreach (const QString &warning, warningMessages)
3265 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3267 QObject *object = component.create();
3268 if (!errorMessage.isEmpty()) {
3269 QVERIFY(object == 0);
3271 QVERIFY(object != 0);
3272 for (int i = 0; i < propertyNames.size(); ++i)
3273 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3278 void tst_qdeclarativeecmascript::scarceResources_other()
3280 /* These tests require knowledge of state, since we test values after
3281 performing signal or function invocation. */
3283 QPixmap origPixmap(100, 100);
3284 origPixmap.fill(Qt::blue);
3285 QString srp_name, expectedWarning;
3286 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3287 ScarceResourceObject *eo = 0;
3289 QObject *object = 0;
3291 /* property var semantics */
3293 // test that scarce resources are handled properly in signal invocation
3294 QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
3295 object = varComponentTen.create();
3296 srsc = object->findChild<QObject*>("srsc");
3298 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3299 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3300 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3301 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3302 QMetaObject::invokeMethod(srsc, "testSignal");
3303 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3304 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3305 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3306 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3307 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3308 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3309 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3310 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3311 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3312 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3315 // test that scarce resources are handled properly from js functions in qml files
3316 QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
3317 object = varComponentEleven.create();
3318 QVERIFY(object != 0);
3319 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3320 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3321 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3322 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3323 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3324 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3325 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3326 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3327 QMetaObject::invokeMethod(object, "releaseScarceResource");
3328 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3329 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3330 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3331 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3334 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3335 QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
3336 object = varComponentTwelve.create();
3337 QVERIFY(object != 0);
3338 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3339 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3340 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3341 srp_name = object->property("srp_name").toString();
3342 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3343 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3344 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3345 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3346 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3347 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3348 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3351 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3352 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3353 QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
3354 object = varComponentThirteen.create();
3355 QVERIFY(object != 0);
3356 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3357 QMetaObject::invokeMethod(object, "assignVarProperty");
3358 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3359 QMetaObject::invokeMethod(object, "deassignVarProperty");
3360 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3363 /* property variant semantics */
3365 // test that scarce resources are handled properly in signal invocation
3366 QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
3367 object = variantComponentTen.create();
3368 QVERIFY(object != 0);
3369 srsc = object->findChild<QObject*>("srsc");
3371 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3372 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3373 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3374 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3375 QMetaObject::invokeMethod(srsc, "testSignal");
3376 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3377 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3378 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3379 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3380 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3381 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3382 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3383 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3384 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3385 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3388 // test that scarce resources are handled properly from js functions in qml files
3389 QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
3390 object = variantComponentEleven.create();
3391 QVERIFY(object != 0);
3392 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3393 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3394 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3395 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3396 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3397 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3398 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3399 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3400 QMetaObject::invokeMethod(object, "releaseScarceResource");
3401 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3402 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3403 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3404 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3407 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3408 QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
3409 object = variantComponentTwelve.create();
3410 QVERIFY(object != 0);
3411 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3412 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3413 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3414 srp_name = object->property("srp_name").toString();
3415 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3416 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3417 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3418 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3419 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3420 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3421 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3425 void tst_qdeclarativeecmascript::scarceResources_data()
3427 QTest::addColumn<QUrl>("qmlFile");
3428 QTest::addColumn<bool>("readDetachStatus");
3429 QTest::addColumn<bool>("expectedDetachStatus");
3430 QTest::addColumn<QStringList>("propertyNames");
3431 QTest::addColumn<QVariantList>("expectedValidity");
3432 QTest::addColumn<QVariantList>("expectedValues");
3433 QTest::addColumn<QStringList>("expectedErrors");
3435 QPixmap origPixmap(100, 100);
3436 origPixmap.fill(Qt::blue);
3438 /* property var semantics */
3440 // in the following three cases, the instance created from the component
3441 // has a property which is a copy of the scarce resource; hence, the
3442 // resource should NOT be detached prior to deletion of the object instance,
3443 // unless the resource is destroyed explicitly.
3444 QTest::newRow("var: import scarce resource copy directly")
3445 << testFileUrl("scarceResourceCopy.var.qml")
3447 << false // won't be detached, because assigned to property and not explicitly released
3448 << (QStringList() << QLatin1String("scarceResourceCopy"))
3449 << (QList<QVariant>() << true)
3450 << (QList<QVariant>() << origPixmap)
3453 QTest::newRow("var: import scarce resource copy from JS")
3454 << testFileUrl("scarceResourceCopyFromJs.var.qml")
3456 << false // won't be detached, because assigned to property and not explicitly released
3457 << (QStringList() << QLatin1String("scarceResourceCopy"))
3458 << (QList<QVariant>() << true)
3459 << (QList<QVariant>() << origPixmap)
3462 QTest::newRow("var: import released scarce resource copy from JS")
3463 << testFileUrl("scarceResourceDestroyedCopy.var.qml")
3465 << true // explicitly released, so it will be detached
3466 << (QStringList() << QLatin1String("scarceResourceCopy"))
3467 << (QList<QVariant>() << false)
3468 << (QList<QVariant>() << QVariant())
3471 // in the following three cases, no other copy should exist in memory,
3472 // and so it should be detached (unless explicitly preserved).
3473 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3474 << testFileUrl("scarceResourceTest.var.qml")
3476 << true // auto released, so it will be detached
3477 << (QStringList() << QLatin1String("scarceResourceTest"))
3478 << (QList<QVariant>() << true)
3479 << (QList<QVariant>() << QVariant(100))
3481 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3482 << testFileUrl("scarceResourceTestPreserve.var.qml")
3484 << false // won't be detached because we explicitly preserve it
3485 << (QStringList() << QLatin1String("scarceResourceTest"))
3486 << (QList<QVariant>() << true)
3487 << (QList<QVariant>() << QVariant(100))
3489 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3490 << testFileUrl("scarceResourceTestMultiple.var.qml")
3492 << true // will be detached because all resources were released manually or automatically.
3493 << (QStringList() << QLatin1String("scarceResourceTest"))
3494 << (QList<QVariant>() << true)
3495 << (QList<QVariant>() << QVariant(100))
3498 // In the following three cases, test that scarce resources are handled
3499 // correctly for imports.
3500 QTest::newRow("var: import with no binding")
3501 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3502 << false // cannot check detach status.
3505 << QList<QVariant>()
3506 << QList<QVariant>()
3508 QTest::newRow("var: import with binding without explicit preserve")
3509 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3512 << (QStringList() << QLatin1String("scarceResourceCopy"))
3513 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3514 << (QList<QVariant>() << QVariant())
3516 QTest::newRow("var: import with explicit release after binding evaluation")
3517 << testFileUrl("scarceResourceCopyImport.var.qml")
3520 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3521 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3522 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3524 QTest::newRow("var: import with different js objects")
3525 << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
3528 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3529 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3530 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3532 QTest::newRow("var: import with different js objects and explicit release")
3533 << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
3536 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3537 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3538 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3540 QTest::newRow("var: import with same js objects and explicit release")
3541 << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
3544 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3545 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3546 << (QList<QVariant>() << QVariant() << QVariant())
3548 QTest::newRow("var: binding with same js objects and explicit release")
3549 << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
3552 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3553 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3554 << (QList<QVariant>() << QVariant() << QVariant())
3558 /* property variant semantics */
3560 // in the following three cases, the instance created from the component
3561 // has a property which is a copy of the scarce resource; hence, the
3562 // resource should NOT be detached prior to deletion of the object instance,
3563 // unless the resource is destroyed explicitly.
3564 QTest::newRow("variant: import scarce resource copy directly")
3565 << testFileUrl("scarceResourceCopy.variant.qml")
3567 << false // won't be detached, because assigned to property and not explicitly released
3568 << (QStringList() << QLatin1String("scarceResourceCopy"))
3569 << (QList<QVariant>() << true)
3570 << (QList<QVariant>() << origPixmap)
3573 QTest::newRow("variant: import scarce resource copy from JS")
3574 << testFileUrl("scarceResourceCopyFromJs.variant.qml")
3576 << false // won't be detached, because assigned to property and not explicitly released
3577 << (QStringList() << QLatin1String("scarceResourceCopy"))
3578 << (QList<QVariant>() << true)
3579 << (QList<QVariant>() << origPixmap)
3582 QTest::newRow("variant: import released scarce resource copy from JS")
3583 << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
3585 << true // explicitly released, so it will be detached
3586 << (QStringList() << QLatin1String("scarceResourceCopy"))
3587 << (QList<QVariant>() << false)
3588 << (QList<QVariant>() << QVariant())
3591 // in the following three cases, no other copy should exist in memory,
3592 // and so it should be detached (unless explicitly preserved).
3593 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3594 << testFileUrl("scarceResourceTest.variant.qml")
3596 << true // auto released, so it will be detached
3597 << (QStringList() << QLatin1String("scarceResourceTest"))
3598 << (QList<QVariant>() << true)
3599 << (QList<QVariant>() << QVariant(100))
3601 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3602 << testFileUrl("scarceResourceTestPreserve.variant.qml")
3604 << false // won't be detached because we explicitly preserve it
3605 << (QStringList() << QLatin1String("scarceResourceTest"))
3606 << (QList<QVariant>() << true)
3607 << (QList<QVariant>() << QVariant(100))
3609 QTest::newRow("variant: import multiple scarce resources")
3610 << testFileUrl("scarceResourceTestMultiple.variant.qml")
3612 << true // will be detached because all resources were released manually or automatically.
3613 << (QStringList() << QLatin1String("scarceResourceTest"))
3614 << (QList<QVariant>() << true)
3615 << (QList<QVariant>() << QVariant(100))
3618 // In the following three cases, test that scarce resources are handled
3619 // correctly for imports.
3620 QTest::newRow("variant: import with no binding")
3621 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3622 << false // cannot check detach status.
3625 << QList<QVariant>()
3626 << QList<QVariant>()
3628 QTest::newRow("variant: import with binding without explicit preserve")
3629 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3632 << (QStringList() << QLatin1String("scarceResourceCopy"))
3633 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3634 << (QList<QVariant>() << QVariant())
3636 QTest::newRow("variant: import with explicit release after binding evaluation")
3637 << testFileUrl("scarceResourceCopyImport.variant.qml")
3640 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3641 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3642 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3646 void tst_qdeclarativeecmascript::scarceResources()
3648 QFETCH(QUrl, qmlFile);
3649 QFETCH(bool, readDetachStatus);
3650 QFETCH(bool, expectedDetachStatus);
3651 QFETCH(QStringList, propertyNames);
3652 QFETCH(QVariantList, expectedValidity);
3653 QFETCH(QVariantList, expectedValues);
3654 QFETCH(QStringList, expectedErrors);
3656 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3657 ScarceResourceObject *eo = 0;
3658 QObject *object = 0;
3660 QDeclarativeComponent c(&engine, qmlFile);
3661 object = c.create();
3662 QVERIFY(object != 0);
3663 for (int i = 0; i < propertyNames.size(); ++i) {
3664 QString prop = propertyNames.at(i);
3665 bool validity = expectedValidity.at(i).toBool();
3666 QVariant value = expectedValues.at(i);
3668 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3669 if (value.type() == QVariant::Int) {
3670 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3671 } else if (value.type() == QVariant::Pixmap) {
3672 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3676 if (readDetachStatus) {
3677 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3678 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3681 QVERIFY(ep->scarceResources.isEmpty());
3685 void tst_qdeclarativeecmascript::propertyChangeSlots()
3687 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3688 QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
3689 QObject *object = component.create();
3690 QVERIFY(object != 0);
3693 // ensure that invalid property names fail properly.
3694 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3695 QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
3696 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3697 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3698 object = e1.create();
3699 QVERIFY(object == 0);
3702 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3703 QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
3704 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3705 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3706 object = e2.create();
3707 QVERIFY(object == 0);
3710 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3711 QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
3712 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3713 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3714 object = e3.create();
3715 QVERIFY(object == 0);
3718 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3719 QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
3720 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3721 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3722 object = e4.create();
3723 QVERIFY(object == 0);
3727 void tst_qdeclarativeecmascript::propertyVar_data()
3729 QTest::addColumn<QUrl>("qmlFile");
3732 QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
3733 QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
3734 QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
3735 QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
3736 QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
3737 QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
3738 QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
3739 QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
3740 QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
3741 QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
3744 void tst_qdeclarativeecmascript::propertyVar()
3746 QFETCH(QUrl, qmlFile);
3748 QDeclarativeComponent component(&engine, qmlFile);
3749 QObject *object = component.create();
3750 QVERIFY(object != 0);
3752 QCOMPARE(object->property("test").toBool(), true);
3757 // Tests that we can write QVariant values to var properties from C++
3758 void tst_qdeclarativeecmascript::propertyVarCpp()
3760 QObject *object = 0;
3762 // ensure that writing to and reading from a var property from cpp works as required.
3763 // Literal values stored in var properties can be read and written as QVariants
3764 // of a specific type, whereas object values are read as QVariantMaps.
3765 QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
3766 object = component.create();
3767 QVERIFY(object != 0);
3768 // assign int to property var that currently has int assigned
3769 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3770 QCOMPARE(object->property("varBound"), QVariant(15));
3771 QCOMPARE(object->property("intBound"), QVariant(15));
3772 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3773 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3774 // assign string to property var that current has bool assigned
3775 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3776 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3777 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3778 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3779 // now enforce behaviour when accessing JavaScript objects from cpp.
3780 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3784 static void gc(QDeclarativeEngine &engine)
3786 engine.collectGarbage();
3787 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
3788 QCoreApplication::processEvents();
3791 void tst_qdeclarativeecmascript::propertyVarOwnership()
3793 // Referenced JS objects are not collected
3795 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
3796 QObject *object = component.create();
3797 QVERIFY(object != 0);
3798 QCOMPARE(object->property("test").toBool(), false);
3799 QMetaObject::invokeMethod(object, "runTest");
3800 QCOMPARE(object->property("test").toBool(), true);
3803 // Referenced JS objects are not collected
3805 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
3806 QObject *object = component.create();
3807 QVERIFY(object != 0);
3808 QCOMPARE(object->property("test").toBool(), false);
3809 QMetaObject::invokeMethod(object, "runTest");
3810 QCOMPARE(object->property("test").toBool(), true);
3813 // Qt objects are not collected until they've been dereferenced
3815 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
3816 QObject *object = component.create();
3817 QVERIFY(object != 0);
3819 QCOMPARE(object->property("test2").toBool(), false);
3820 QCOMPARE(object->property("test2").toBool(), false);
3822 QMetaObject::invokeMethod(object, "runTest");
3823 QCOMPARE(object->property("test1").toBool(), true);
3825 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3826 QVERIFY(!referencedObject.isNull());
3828 QVERIFY(!referencedObject.isNull());
3830 QMetaObject::invokeMethod(object, "runTest2");
3831 QCOMPARE(object->property("test2").toBool(), true);
3833 QVERIFY(referencedObject.isNull());
3837 // Self reference does not prevent Qt object collection
3839 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
3840 QObject *object = component.create();
3841 QVERIFY(object != 0);
3843 QCOMPARE(object->property("test").toBool(), true);
3845 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3846 QVERIFY(!referencedObject.isNull());
3848 QVERIFY(!referencedObject.isNull());
3850 QMetaObject::invokeMethod(object, "runTest");
3852 QVERIFY(referencedObject.isNull());
3858 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3860 // The childObject has a reference to a different QObject. We want to ensure
3861 // that the different item will not be cleaned up until required. IE, the childObject
3862 // has implicit ownership of the constructed QObject.
3863 QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
3864 QObject *object = component.create();
3865 QVERIFY(object != 0);
3866 QMetaObject::invokeMethod(object, "assignCircular");
3867 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3868 QCoreApplication::processEvents();
3869 QObject *rootObject = object->property("vp").value<QObject*>();
3870 QVERIFY(rootObject != 0);
3871 QObject *childObject = rootObject->findChild<QObject*>("text");
3872 QVERIFY(childObject != 0);
3873 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3874 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3875 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3876 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3877 QVERIFY(!qobjectGuard.isNull());
3878 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3879 QCoreApplication::processEvents();
3880 QVERIFY(!qobjectGuard.isNull());
3881 QMetaObject::invokeMethod(object, "deassignCircular");
3882 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3883 QCoreApplication::processEvents();
3884 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3888 void tst_qdeclarativeecmascript::propertyVarReparent()
3890 // ensure that nothing breaks if we re-parent objects
3891 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3892 QObject *object = component.create();
3893 QVERIFY(object != 0);
3894 QMetaObject::invokeMethod(object, "assignVarProp");
3895 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3896 QCoreApplication::processEvents();
3897 QObject *rect = object->property("vp").value<QObject*>();
3898 QObject *text = rect->findChild<QObject*>("textOne");
3899 QObject *text2 = rect->findChild<QObject*>("textTwo");
3900 QWeakPointer<QObject> rectGuard(rect);
3901 QWeakPointer<QObject> textGuard(text);
3902 QWeakPointer<QObject> text2Guard(text2);
3903 QVERIFY(!rectGuard.isNull());
3904 QVERIFY(!textGuard.isNull());
3905 QVERIFY(!text2Guard.isNull());
3906 QCOMPARE(text->property("textCanary").toInt(), 11);
3907 QCOMPARE(text2->property("textCanary").toInt(), 12);
3908 // now construct an image which we will reparent.
3909 QMetaObject::invokeMethod(text2, "constructQObject");
3910 QObject *image = text2->property("vp").value<QObject*>();
3911 QWeakPointer<QObject> imageGuard(image);
3912 QVERIFY(!imageGuard.isNull());
3913 QCOMPARE(image->property("imageCanary").toInt(), 13);
3914 // now reparent the "Image" object (currently, it has JS ownership)
3915 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3916 QMetaObject::invokeMethod(text2, "deassignVp");
3917 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3918 QCoreApplication::processEvents();
3919 QCOMPARE(text->property("textCanary").toInt(), 11);
3920 QCOMPARE(text2->property("textCanary").toInt(), 22);
3921 QVERIFY(!imageGuard.isNull()); // should still be alive.
3922 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3923 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3924 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3925 QCoreApplication::processEvents();
3926 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3930 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3932 // sometimes reparenting can cause problems
3933 // (eg, if the ctxt is collected, varproperties are no longer available)
3934 // this test ensures that no crash occurs in that situation.
3935 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3936 QObject *object = component.create();
3937 QVERIFY(object != 0);
3938 QMetaObject::invokeMethod(object, "assignVarProp");
3939 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3940 QCoreApplication::processEvents();
3941 QObject *rect = object->property("vp").value<QObject*>();
3942 QObject *text = rect->findChild<QObject*>("textOne");
3943 QObject *text2 = rect->findChild<QObject*>("textTwo");
3944 QWeakPointer<QObject> rectGuard(rect);
3945 QWeakPointer<QObject> textGuard(text);
3946 QWeakPointer<QObject> text2Guard(text2);
3947 QVERIFY(!rectGuard.isNull());
3948 QVERIFY(!textGuard.isNull());
3949 QVERIFY(!text2Guard.isNull());
3950 QCOMPARE(text->property("textCanary").toInt(), 11);
3951 QCOMPARE(text2->property("textCanary").toInt(), 12);
3952 // now construct an image which we will reparent.
3953 QMetaObject::invokeMethod(text2, "constructQObject");
3954 QObject *image = text2->property("vp").value<QObject*>();
3955 QWeakPointer<QObject> imageGuard(image);
3956 QVERIFY(!imageGuard.isNull());
3957 QCOMPARE(image->property("imageCanary").toInt(), 13);
3958 // now reparent the "Image" object (currently, it has JS ownership)
3959 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3960 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3961 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3962 QCoreApplication::processEvents();
3963 QVERIFY(!imageGuard.isNull()); // should still be alive.
3964 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3966 QVERIFY(imageGuard.isNull()); // should now be dead.
3969 void tst_qdeclarativeecmascript::propertyVarCircular()
3971 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3972 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
3973 QObject *object = component.create();
3974 QVERIFY(object != 0);
3975 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3976 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3977 QCoreApplication::processEvents();
3978 QCOMPARE(object->property("canaryInt"), QVariant(5));
3979 QVariant canaryResourceVariant = object->property("canaryResource");
3980 QVERIFY(canaryResourceVariant.isValid());
3981 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3982 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3983 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3984 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3985 QCoreApplication::processEvents();
3986 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3987 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3988 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3989 QCoreApplication::processEvents();
3990 QCOMPARE(object->property("canaryInt"), QVariant(2));
3991 QCOMPARE(object->property("canaryResource"), QVariant(1));
3992 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3996 void tst_qdeclarativeecmascript::propertyVarCircular2()
3998 // track deletion of JS-owned parent item with Cpp-owned child
3999 // where the child has a var property referencing its parent.
4000 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4001 QObject *object = component.create();
4002 QVERIFY(object != 0);
4003 QMetaObject::invokeMethod(object, "assignCircular");
4004 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4005 QCoreApplication::processEvents();
4006 QObject *rootObject = object->property("vp").value<QObject*>();
4007 QVERIFY(rootObject != 0);
4008 QObject *childObject = rootObject->findChild<QObject*>("text");
4009 QVERIFY(childObject != 0);
4010 QWeakPointer<QObject> rootObjectTracker(rootObject);
4011 QVERIFY(!rootObjectTracker.isNull());
4012 QWeakPointer<QObject> childObjectTracker(childObject);
4013 QVERIFY(!childObjectTracker.isNull());
4015 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4016 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4017 QMetaObject::invokeMethod(object, "deassignCircular");
4018 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4019 QCoreApplication::processEvents();
4020 QVERIFY(rootObjectTracker.isNull()); // should have been collected
4021 QVERIFY(childObjectTracker.isNull()); // should have been collected
4025 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
4027 *(int*)(parameter) += 1;
4028 qPersistentDispose(object);
4031 void tst_qdeclarativeecmascript::propertyVarInheritance()
4033 int propertyVarWeakRefCallbackCount = 0;
4035 // enforce behaviour regarding element inheritance - ensure handle disposal.
4036 // The particular component under test here has a chain of references.
4037 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
4038 QObject *object = component.create();
4039 QVERIFY(object != 0);
4040 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
4041 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4042 QCoreApplication::processEvents();
4043 // we want to be able to track when the varProperties array of the last metaobject is disposed
4044 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
4045 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*>();
4046 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
4047 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
4048 v8::Persistent<v8::Value> icoCanaryHandle;
4049 v8::Persistent<v8::Value> ccoCanaryHandle;
4052 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4053 // public function which can return us a handle to something in the varProperties array.
4054 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4055 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4056 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4057 // as the varproperties array of each vmemo still references the resource.
4058 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4059 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4061 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4063 // now we deassign the var prop, which should trigger collection of item subtrees.
4064 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4065 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4066 QCoreApplication::processEvents();
4067 // ensure that there are only weak handles to the underlying varProperties array remaining.
4069 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4071 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4072 // to what remains are weak, all varProperties arrays must have been collected.
4075 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4077 int propertyVarWeakRefCallbackCount = 0;
4079 // The particular component under test here does NOT have a chain of references; the
4080 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4081 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4082 QObject *object = component.create();
4083 QVERIFY(object != 0);
4084 QMetaObject::invokeMethod(object, "assignCircular");
4085 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4086 QCoreApplication::processEvents();
4087 QObject *rootObject = object->property("vp").value<QObject*>();
4088 QVERIFY(rootObject != 0);
4089 QObject *childObject = rootObject->findChild<QObject*>("text");
4090 QVERIFY(childObject != 0);
4091 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4092 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4093 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4096 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4097 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
4098 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4100 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4101 QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
4102 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4104 QMetaObject::invokeMethod(object, "deassignCircular");
4105 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4106 QCoreApplication::processEvents();
4107 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4111 // Ensure that QObject type conversion works on binding assignment
4112 void tst_qdeclarativeecmascript::elementAssign()
4114 QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
4116 QObject *object = component.create();
4117 QVERIFY(object != 0);
4119 QCOMPARE(object->property("test").toBool(), true);
4125 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4127 QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
4129 QObject *object = component.create();
4130 QVERIFY(object != 0);
4132 QCOMPARE(object->property("test").toBool(), true);
4138 void tst_qdeclarativeecmascript::objectConversion()
4140 QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
4142 QObject *object = component.create();
4143 QVERIFY(object != 0);
4145 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4146 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4153 void tst_qdeclarativeecmascript::booleanConversion()
4155 QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
4157 QObject *object = component.create();
4158 QVERIFY(object != 0);
4160 QCOMPARE(object->property("test_true1").toBool(), true);
4161 QCOMPARE(object->property("test_true2").toBool(), true);
4162 QCOMPARE(object->property("test_true3").toBool(), true);
4163 QCOMPARE(object->property("test_true4").toBool(), true);
4164 QCOMPARE(object->property("test_true5").toBool(), true);
4166 QCOMPARE(object->property("test_false1").toBool(), false);
4167 QCOMPARE(object->property("test_false2").toBool(), false);
4168 QCOMPARE(object->property("test_false3").toBool(), false);
4173 void tst_qdeclarativeecmascript::handleReferenceManagement()
4178 // Linear QObject reference
4179 QDeclarativeEngine hrmEngine;
4180 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
4181 QObject *object = component.create();
4182 QVERIFY(object != 0);
4183 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4184 cro->setEngine(&hrmEngine);
4185 cro->setDtorCount(&dtorCount);
4186 QMetaObject::invokeMethod(object, "createReference");
4188 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4190 hrmEngine.collectGarbage();
4191 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4192 QCoreApplication::processEvents();
4193 QCOMPARE(dtorCount, 3);
4198 // Circular QObject reference
4199 QDeclarativeEngine hrmEngine;
4200 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
4201 QObject *object = component.create();
4202 QVERIFY(object != 0);
4203 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4204 cro->setEngine(&hrmEngine);
4205 cro->setDtorCount(&dtorCount);
4206 QMetaObject::invokeMethod(object, "circularReference");
4208 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4210 hrmEngine.collectGarbage();
4211 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4212 QCoreApplication::processEvents();
4213 QCOMPARE(dtorCount, 3);
4218 // Linear handle reference
4219 QDeclarativeEngine hrmEngine;
4220 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
4221 QObject *object = component.create();
4222 QVERIFY(object != 0);
4223 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4225 crh->setEngine(&hrmEngine);
4226 crh->setDtorCount(&dtorCount);
4227 QMetaObject::invokeMethod(object, "createReference");
4228 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4229 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4230 QVERIFY(first != 0);
4231 QVERIFY(second != 0);
4232 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4233 // now we have to reparent second and make second owned by JS.
4234 second->setParent(0);
4235 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4237 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4239 hrmEngine.collectGarbage();
4240 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4241 QCoreApplication::processEvents();
4242 QCOMPARE(dtorCount, 3);
4247 // Circular handle reference
4248 QDeclarativeEngine hrmEngine;
4249 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
4250 QObject *object = component.create();
4251 QVERIFY(object != 0);
4252 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4254 crh->setEngine(&hrmEngine);
4255 crh->setDtorCount(&dtorCount);
4256 QMetaObject::invokeMethod(object, "circularReference");
4257 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4258 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4259 QVERIFY(first != 0);
4260 QVERIFY(second != 0);
4261 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4262 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4263 // now we have to reparent and change ownership.
4264 first->setParent(0);
4265 second->setParent(0);
4266 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4267 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4269 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4271 hrmEngine.collectGarbage();
4272 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4273 QCoreApplication::processEvents();
4274 QCOMPARE(dtorCount, 3);
4279 // multiple engine interaction - linear reference
4280 QDeclarativeEngine hrmEngine1;
4281 QDeclarativeEngine hrmEngine2;
4282 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4283 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4284 QObject *object1 = component1.create();
4285 QObject *object2 = component2.create();
4286 QVERIFY(object1 != 0);
4287 QVERIFY(object2 != 0);
4288 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4289 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4292 crh1->setEngine(&hrmEngine1);
4293 crh2->setEngine(&hrmEngine2);
4294 crh1->setDtorCount(&dtorCount);
4295 crh2->setDtorCount(&dtorCount);
4296 QMetaObject::invokeMethod(object1, "createReference");
4297 QMetaObject::invokeMethod(object2, "createReference");
4298 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4299 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4300 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4301 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4302 QVERIFY(first1 != 0);
4303 QVERIFY(second1 != 0);
4304 QVERIFY(first2 != 0);
4305 QVERIFY(second2 != 0);
4306 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4307 // now we have to reparent second2 and make second2 owned by JS.
4308 second2->setParent(0);
4309 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4311 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4312 QCoreApplication::processEvents();
4313 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4316 hrmEngine1.collectGarbage();
4317 hrmEngine2.collectGarbage();
4318 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4319 QCoreApplication::processEvents();
4320 QCOMPARE(dtorCount, 6);
4325 // multiple engine interaction - circular reference
4326 QDeclarativeEngine hrmEngine1;
4327 QDeclarativeEngine hrmEngine2;
4328 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4329 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4330 QObject *object1 = component1.create();
4331 QObject *object2 = component2.create();
4332 QVERIFY(object1 != 0);
4333 QVERIFY(object2 != 0);
4334 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4335 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4338 crh1->setEngine(&hrmEngine1);
4339 crh2->setEngine(&hrmEngine2);
4340 crh1->setDtorCount(&dtorCount);
4341 crh2->setDtorCount(&dtorCount);
4342 QMetaObject::invokeMethod(object1, "createReference");
4343 QMetaObject::invokeMethod(object2, "createReference");
4344 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4345 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4346 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4347 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4348 QVERIFY(first1 != 0);
4349 QVERIFY(second1 != 0);
4350 QVERIFY(first2 != 0);
4351 QVERIFY(second2 != 0);
4352 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4353 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4354 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4355 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4356 // now we have to reparent and change ownership to JS.
4357 first1->setParent(0);
4358 second1->setParent(0);
4359 first2->setParent(0);
4360 second2->setParent(0);
4361 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4362 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4363 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4364 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4366 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4367 QCoreApplication::processEvents();
4368 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4371 hrmEngine1.collectGarbage();
4372 hrmEngine2.collectGarbage();
4373 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4374 QCoreApplication::processEvents();
4375 QCOMPARE(dtorCount, 6);
4380 // multiple engine interaction - linear reference with engine deletion
4381 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4382 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4383 QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4384 QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4385 QObject *object1 = component1.create();
4386 QObject *object2 = component2.create();
4387 QVERIFY(object1 != 0);
4388 QVERIFY(object2 != 0);
4389 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4390 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4393 crh1->setEngine(hrmEngine1);
4394 crh2->setEngine(hrmEngine2);
4395 crh1->setDtorCount(&dtorCount);
4396 crh2->setDtorCount(&dtorCount);
4397 QMetaObject::invokeMethod(object1, "createReference");
4398 QMetaObject::invokeMethod(object2, "createReference");
4399 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4400 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4401 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4402 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4403 QVERIFY(first1 != 0);
4404 QVERIFY(second1 != 0);
4405 QVERIFY(first2 != 0);
4406 QVERIFY(second2 != 0);
4407 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4408 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4409 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4410 // now we have to reparent and change ownership to JS.
4411 first1->setParent(crh1);
4412 second1->setParent(0);
4413 first2->setParent(0);
4414 second2->setParent(0);
4415 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4416 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4417 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4419 QCOMPARE(dtorCount, 0);
4422 QCOMPARE(dtorCount, 0);
4425 hrmEngine1->collectGarbage();
4426 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4427 QCoreApplication::processEvents();
4428 QCOMPARE(dtorCount, 6);
4433 void tst_qdeclarativeecmascript::stringArg()
4435 QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
4436 QObject *object = component.create();
4437 QVERIFY(object != 0);
4438 QMetaObject::invokeMethod(object, "success");
4439 QVERIFY(object->property("returnValue").toBool());
4441 QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4442 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4443 QMetaObject::invokeMethod(object, "failure");
4444 QVERIFY(object->property("returnValue").toBool());
4449 void tst_qdeclarativeecmascript::readonlyDeclaration()
4451 QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
4453 QObject *object = component.create();
4454 QVERIFY(object != 0);
4456 QCOMPARE(object->property("test").toBool(), true);
4461 Q_DECLARE_METATYPE(QList<int>)
4462 Q_DECLARE_METATYPE(QList<qreal>)
4463 Q_DECLARE_METATYPE(QList<bool>)
4464 Q_DECLARE_METATYPE(QList<QString>)
4465 Q_DECLARE_METATYPE(QList<QUrl>)
4466 void tst_qdeclarativeecmascript::sequenceConversionRead()
4469 QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
4470 QDeclarativeComponent component(&engine, qmlFile);
4471 QObject *object = component.create();
4472 QVERIFY(object != 0);
4473 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4476 QMetaObject::invokeMethod(object, "readSequences");
4477 QList<int> intList; intList << 1 << 2 << 3 << 4;
4478 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4479 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4480 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4481 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4482 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4483 QList<bool> boolList; boolList << true << false << true << false;
4484 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4485 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4486 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4487 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4488 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4489 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4490 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4491 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4492 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4493 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4494 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4496 QMetaObject::invokeMethod(object, "readSequenceElements");
4497 QCOMPARE(object->property("intVal").toInt(), 2);
4498 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4499 QCOMPARE(object->property("boolVal").toBool(), false);
4500 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4501 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4502 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4504 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4505 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4507 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4508 QDeclarativeProperty seqProp(seq, "intListProperty");
4509 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4510 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4511 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4513 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4514 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4520 QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
4521 QDeclarativeComponent component(&engine, qmlFile);
4522 QObject *object = component.create();
4523 QVERIFY(object != 0);
4524 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4527 // we haven't registered QList<QPoint> as a sequence type.
4528 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4529 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4530 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4531 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4533 QMetaObject::invokeMethod(object, "performTest");
4535 // QList<QPoint> has not been registered as a sequence type.
4536 QCOMPARE(object->property("pointListLength").toInt(), 0);
4537 QVERIFY(!object->property("pointList").isValid());
4538 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4539 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4540 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4546 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4549 QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
4550 QDeclarativeComponent component(&engine, qmlFile);
4551 QObject *object = component.create();
4552 QVERIFY(object != 0);
4553 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4556 QMetaObject::invokeMethod(object, "writeSequences");
4557 QCOMPARE(object->property("success").toBool(), true);
4559 QMetaObject::invokeMethod(object, "writeSequenceElements");
4560 QCOMPARE(object->property("success").toBool(), true);
4562 QMetaObject::invokeMethod(object, "writeOtherElements");
4563 QCOMPARE(object->property("success").toBool(), true);
4565 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4566 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4572 QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
4573 QDeclarativeComponent component(&engine, qmlFile);
4574 QObject *object = component.create();
4575 QVERIFY(object != 0);
4576 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4579 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4580 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4581 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4583 QMetaObject::invokeMethod(object, "performTest");
4585 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4586 QCOMPARE(seq->pointListProperty(), pointList);
4592 void tst_qdeclarativeecmascript::sequenceConversionArray()
4594 // ensure that in JS the returned sequences act just like normal JS Arrays.
4595 QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
4596 QDeclarativeComponent component(&engine, qmlFile);
4597 QObject *object = component.create();
4598 QVERIFY(object != 0);
4599 QMetaObject::invokeMethod(object, "indexedAccess");
4600 QVERIFY(object->property("success").toBool());
4601 QMetaObject::invokeMethod(object, "arrayOperations");
4602 QVERIFY(object->property("success").toBool());
4603 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4604 QVERIFY(object->property("success").toBool());
4605 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4606 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4610 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4612 // ensure that sequence conversion operations work correctly in a worker thread
4613 // and that serialisation between the main and worker thread succeeds.
4614 QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
4615 QDeclarativeComponent component(&engine, qmlFile);
4616 QObject *object = component.create();
4617 QVERIFY(object != 0);
4619 QMetaObject::invokeMethod(object, "testIntSequence");
4620 QTRY_VERIFY(object->property("finished").toBool());
4621 QVERIFY(object->property("success").toBool());
4623 QMetaObject::invokeMethod(object, "testQrealSequence");
4624 QTRY_VERIFY(object->property("finished").toBool());
4625 QVERIFY(object->property("success").toBool());
4627 QMetaObject::invokeMethod(object, "testBoolSequence");
4628 QTRY_VERIFY(object->property("finished").toBool());
4629 QVERIFY(object->property("success").toBool());
4631 QMetaObject::invokeMethod(object, "testStringSequence");
4632 QTRY_VERIFY(object->property("finished").toBool());
4633 QVERIFY(object->property("success").toBool());
4635 QMetaObject::invokeMethod(object, "testQStringSequence");
4636 QTRY_VERIFY(object->property("finished").toBool());
4637 QVERIFY(object->property("success").toBool());
4639 QMetaObject::invokeMethod(object, "testUrlSequence");
4640 QTRY_VERIFY(object->property("finished").toBool());
4641 QVERIFY(object->property("success").toBool());
4643 QMetaObject::invokeMethod(object, "testVariantSequence");
4644 QTRY_VERIFY(object->property("finished").toBool());
4645 QVERIFY(object->property("success").toBool());
4650 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4653 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
4654 QDeclarativeComponent component(&engine, qmlFile);
4655 QObject *object = component.create();
4656 QVERIFY(object != 0);
4657 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4658 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4659 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4660 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4661 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4666 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
4667 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4668 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4669 QDeclarativeComponent component(&engine, qmlFile);
4670 QObject *object = component.create();
4671 QVERIFY(object != 0);
4676 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4678 QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
4679 QDeclarativeComponent component(&engine, qmlFile);
4680 QObject *object = component.create();
4681 QVERIFY(object != 0);
4682 QMetaObject::invokeMethod(object, "testCopySequences");
4683 QCOMPARE(object->property("success").toBool(), true);
4684 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4685 QCOMPARE(object->property("success").toBool(), true);
4686 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4687 QCOMPARE(object->property("success").toBool(), true);
4691 void tst_qdeclarativeecmascript::assignSequenceTypes()
4693 // test binding array to sequence type property
4695 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
4696 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4697 QVERIFY(object != 0);
4698 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4699 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4700 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4701 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4702 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4703 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4707 // test binding literal to sequence type property
4709 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
4710 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4711 QVERIFY(object != 0);
4712 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4713 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4714 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4715 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4716 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4717 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4721 // test binding single value to sequence type property
4723 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
4724 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4725 QVERIFY(object != 0);
4726 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4727 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4728 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4729 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4733 // test assigning array to sequence type property in js function
4735 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
4736 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4737 QVERIFY(object != 0);
4738 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4739 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4740 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4741 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4742 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4743 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4747 // test assigning literal to sequence type property in js function
4749 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
4750 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4751 QVERIFY(object != 0);
4752 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4753 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4754 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4755 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4756 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4757 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4761 // test assigning single value to sequence type property in js function
4763 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
4764 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4765 QVERIFY(object != 0);
4766 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4767 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4768 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4769 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4773 // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
4775 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
4776 QObject *object = component.create();
4777 QVERIFY(object != 0);
4778 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
4779 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
4780 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
4781 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
4782 MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
4783 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
4784 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4785 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4786 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4787 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4788 QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4793 // Test that assigning a null object works
4794 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4795 void tst_qdeclarativeecmascript::nullObjectBinding()
4797 QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
4799 QObject *object = component.create();
4800 QVERIFY(object != 0);
4802 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4807 // Test that bindings don't evaluate once the engine has been destroyed
4808 void tst_qdeclarativeecmascript::deletedEngine()
4810 QDeclarativeEngine *engine = new QDeclarativeEngine;
4811 QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
4813 QObject *object = component.create();
4814 QVERIFY(object != 0);
4816 QCOMPARE(object->property("a").toInt(), 39);
4817 object->setProperty("b", QVariant(9));
4818 QCOMPARE(object->property("a").toInt(), 117);
4822 QCOMPARE(object->property("a").toInt(), 117);
4823 object->setProperty("b", QVariant(10));
4824 QCOMPARE(object->property("a").toInt(), 117);
4829 // Test the crashing part of QTBUG-9705
4830 void tst_qdeclarativeecmascript::libraryScriptAssert()
4832 QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
4834 QObject *object = component.create();
4835 QVERIFY(object != 0);
4840 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4842 QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
4844 QObject *object = component.create();
4845 QVERIFY(object != 0);
4847 QCOMPARE(object->property("test1").toInt(), 10);
4848 QCOMPARE(object->property("test2").toInt(), 11);
4850 object->setProperty("runTest", true);
4852 QCOMPARE(object->property("test1"), QVariant());
4853 QCOMPARE(object->property("test2"), QVariant());
4859 void tst_qdeclarativeecmascript::qtbug_9792()
4861 QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
4863 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4865 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4866 QVERIFY(object != 0);
4868 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4869 object->basicSignal();
4873 transientErrorsMsgCount = 0;
4874 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4876 object->basicSignal();
4878 qInstallMsgHandler(old);
4880 QCOMPARE(transientErrorsMsgCount, 0);
4885 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4886 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4888 QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
4890 QObject *o = component.create();
4893 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4894 QVERIFY(nested != 0);
4896 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4899 nested = qvariant_cast<QObject *>(o->property("object"));
4900 QVERIFY(nested == 0);
4902 // If the bug is present, the next line will crash
4906 // Test that we shut down without stupid warnings
4907 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4910 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
4912 QObject *o = component.create();
4914 transientErrorsMsgCount = 0;
4915 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4919 qInstallMsgHandler(old);
4921 QCOMPARE(transientErrorsMsgCount, 0);
4926 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
4928 QObject *o = component.create();
4930 transientErrorsMsgCount = 0;
4931 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4935 qInstallMsgHandler(old);
4937 QCOMPARE(transientErrorsMsgCount, 0);
4941 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4944 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
4946 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4949 QVERIFY(o->objectProperty() != 0);
4951 o->setProperty("runTest", true);
4953 QVERIFY(o->objectProperty() == 0);
4959 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
4961 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4964 QVERIFY(o->objectProperty() == 0);
4970 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4972 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
4974 QString url = component.url().toString();
4975 QString warning = url + ":4: Unable to assign a function to a property.";
4976 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4978 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4981 QVERIFY(!o->property("a").isValid());
4986 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4988 QFETCH(QString, triggerProperty);
4990 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4991 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4993 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4995 QVERIFY(!o->property("a").isValid());
4997 o->setProperty("aNumber", QVariant(5));
4998 o->setProperty(triggerProperty.toUtf8().constData(), true);
4999 QCOMPARE(o->property("a"), QVariant(50));
5001 o->setProperty("aNumber", QVariant(10));
5002 QCOMPARE(o->property("a"), QVariant(100));
5007 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
5009 QTest::addColumn<QString>("triggerProperty");
5011 QTest::newRow("assign to property") << "assignToProperty";
5012 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
5014 QTest::newRow("assign to value type") << "assignToValueType";
5016 QTest::newRow("use 'this'") << "assignWithThis";
5017 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
5020 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
5022 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
5023 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
5025 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5027 QVERIFY(!o->property("a").isValid());
5029 o->setProperty("assignFuncWithoutReturn", true);
5030 QVERIFY(!o->property("a").isValid());
5032 QString url = component.url().toString();
5033 QString warning = url + ":67: Unable to assign QString to int";
5034 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5035 o->setProperty("assignWrongType", true);
5037 warning = url + ":71: Unable to assign QString to int";
5038 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5039 o->setProperty("assignWrongTypeToValueType", true);
5044 void tst_qdeclarativeecmascript::eval()
5046 QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
5048 QObject *o = component.create();
5051 QCOMPARE(o->property("test1").toBool(), true);
5052 QCOMPARE(o->property("test2").toBool(), true);
5053 QCOMPARE(o->property("test3").toBool(), true);
5054 QCOMPARE(o->property("test4").toBool(), true);
5055 QCOMPARE(o->property("test5").toBool(), true);
5060 void tst_qdeclarativeecmascript::function()
5062 QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
5064 QObject *o = component.create();
5067 QCOMPARE(o->property("test1").toBool(), true);
5068 QCOMPARE(o->property("test2").toBool(), true);
5069 QCOMPARE(o->property("test3").toBool(), true);
5074 // Test the "Qt.include" method
5075 void tst_qdeclarativeecmascript::include()
5077 // Non-library relative include
5079 QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
5080 QObject *o = component.create();
5083 QCOMPARE(o->property("test0").toInt(), 99);
5084 QCOMPARE(o->property("test1").toBool(), true);
5085 QCOMPARE(o->property("test2").toBool(), true);
5086 QCOMPARE(o->property("test2_1").toBool(), true);
5087 QCOMPARE(o->property("test3").toBool(), true);
5088 QCOMPARE(o->property("test3_1").toBool(), true);
5093 // Library relative include
5095 QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
5096 QObject *o = component.create();
5099 QCOMPARE(o->property("test0").toInt(), 99);
5100 QCOMPARE(o->property("test1").toBool(), true);
5101 QCOMPARE(o->property("test2").toBool(), true);
5102 QCOMPARE(o->property("test2_1").toBool(), true);
5103 QCOMPARE(o->property("test3").toBool(), true);
5104 QCOMPARE(o->property("test3_1").toBool(), true);
5111 QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
5112 QObject *o = component.create();
5115 QCOMPARE(o->property("test1").toBool(), true);
5116 QCOMPARE(o->property("test2").toBool(), true);
5117 QCOMPARE(o->property("test3").toBool(), true);
5118 QCOMPARE(o->property("test4").toBool(), true);
5119 QCOMPARE(o->property("test5").toBool(), true);
5120 QCOMPARE(o->property("test6").toBool(), true);
5125 // Including file with ".pragma library"
5127 QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
5128 QObject *o = component.create();
5130 QCOMPARE(o->property("test1").toInt(), 100);
5137 TestHTTPServer server(8111);
5138 QVERIFY(server.isValid());
5139 server.serveDirectory(dataDirectory());
5141 QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
5142 QObject *o = component.create();
5145 QTRY_VERIFY(o->property("done").toBool() == true);
5146 QTRY_VERIFY(o->property("done2").toBool() == true);
5148 QCOMPARE(o->property("test1").toBool(), true);
5149 QCOMPARE(o->property("test2").toBool(), true);
5150 QCOMPARE(o->property("test3").toBool(), true);
5151 QCOMPARE(o->property("test4").toBool(), true);
5152 QCOMPARE(o->property("test5").toBool(), true);
5154 QCOMPARE(o->property("test6").toBool(), true);
5155 QCOMPARE(o->property("test7").toBool(), true);
5156 QCOMPARE(o->property("test8").toBool(), true);
5157 QCOMPARE(o->property("test9").toBool(), true);
5158 QCOMPARE(o->property("test10").toBool(), true);
5165 TestHTTPServer server(8111);
5166 QVERIFY(server.isValid());
5167 server.serveDirectory(dataDirectory());
5169 QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
5170 QObject *o = component.create();
5173 QTRY_VERIFY(o->property("done").toBool() == true);
5175 QCOMPARE(o->property("test1").toBool(), true);
5176 QCOMPARE(o->property("test2").toBool(), true);
5177 QCOMPARE(o->property("test3").toBool(), true);
5183 void tst_qdeclarativeecmascript::signalHandlers()
5185 QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
5186 QObject *o = component.create();
5189 QVERIFY(o->property("count").toInt() == 0);
5190 QMetaObject::invokeMethod(o, "testSignalCall");
5191 QCOMPARE(o->property("count").toInt(), 1);
5193 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5194 QCOMPARE(o->property("count").toInt(), 1);
5195 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5197 QVERIFY(o->property("funcCount").toInt() == 0);
5198 QMetaObject::invokeMethod(o, "testSignalConnection");
5199 QCOMPARE(o->property("funcCount").toInt(), 1);
5201 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5202 QCOMPARE(o->property("funcCount").toInt(), 2);
5204 QMetaObject::invokeMethod(o, "testSignalDefined");
5205 QCOMPARE(o->property("definedResult").toBool(), true);
5207 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5208 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5213 void tst_qdeclarativeecmascript::qtbug_10696()
5215 QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
5216 QObject *o = component.create();
5221 void tst_qdeclarativeecmascript::qtbug_11606()
5223 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
5224 QObject *o = component.create();
5226 QCOMPARE(o->property("test").toBool(), true);
5230 void tst_qdeclarativeecmascript::qtbug_11600()
5232 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
5233 QObject *o = component.create();
5235 QCOMPARE(o->property("test").toBool(), true);
5239 void tst_qdeclarativeecmascript::qtbug_21864()
5241 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
5242 QObject *o = component.create();
5244 QCOMPARE(o->property("test").toBool(), true);
5248 void tst_qdeclarativeecmascript::rewriteMultiLineStrings()
5251 QDeclarativeComponent component(&engine, testFileUrl("rewriteMultiLineStrings.qml"));
5252 QObject *o = component.create();
5254 QTRY_COMPARE(o->property("test").toBool(), true);
5258 void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
5261 QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
5262 QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
5263 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5264 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5265 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5266 QObject *o = component.create();
5268 QCOMPARE(o->property("test").toBool(), true);
5272 // Reading and writing non-scriptable properties should fail
5273 void tst_qdeclarativeecmascript::nonscriptable()
5275 QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
5276 QObject *o = component.create();
5278 QCOMPARE(o->property("readOk").toBool(), true);
5279 QCOMPARE(o->property("writeOk").toBool(), true);
5283 // deleteLater() should not be callable from QML
5284 void tst_qdeclarativeecmascript::deleteLater()
5286 QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
5287 QObject *o = component.create();
5289 QCOMPARE(o->property("test").toBool(), true);
5293 void tst_qdeclarativeecmascript::in()
5295 QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
5296 QObject *o = component.create();
5298 QCOMPARE(o->property("test1").toBool(), true);
5299 QCOMPARE(o->property("test2").toBool(), true);
5303 void tst_qdeclarativeecmascript::typeOf()
5305 QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
5307 // These warnings should not happen once QTBUG-21864 is fixed
5308 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5309 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5311 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5312 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5314 QObject *o = component.create();
5317 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5318 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5319 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5320 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5321 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5322 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5323 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5324 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5325 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5326 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5331 void tst_qdeclarativeecmascript::sharedAttachedObject()
5333 QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
5334 QObject *o = component.create();
5336 QCOMPARE(o->property("test1").toBool(), true);
5337 QCOMPARE(o->property("test2").toBool(), true);
5342 void tst_qdeclarativeecmascript::objectName()
5344 QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
5345 QObject *o = component.create();
5348 QCOMPARE(o->property("test1").toString(), QString("hello"));
5349 QCOMPARE(o->property("test2").toString(), QString("ell"));
5351 o->setObjectName("world");
5353 QCOMPARE(o->property("test1").toString(), QString("world"));
5354 QCOMPARE(o->property("test2").toString(), QString("orl"));
5359 void tst_qdeclarativeecmascript::writeRemovesBinding()
5361 QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
5362 QObject *o = component.create();
5365 QCOMPARE(o->property("test").toBool(), true);
5370 // Test bindings assigned to alias properties actually assign to the alias' target
5371 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5373 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
5374 QObject *o = component.create();
5377 QCOMPARE(o->property("test").toBool(), true);
5382 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5383 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5386 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
5387 QObject *o = component.create();
5390 QCOMPARE(o->property("test").toBool(), true);
5396 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
5397 QObject *o = component.create();
5400 QCOMPARE(o->property("test").toBool(), true);
5406 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
5407 QObject *o = component.create();
5410 QCOMPARE(o->property("test").toBool(), true);
5416 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5417 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5420 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
5421 QObject *o = component.create();
5424 QCOMPARE(o->property("test").toBool(), true);
5430 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
5431 QObject *o = component.create();
5434 QCOMPARE(o->property("test").toBool(), true);
5440 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
5441 QObject *o = component.create();
5444 QCOMPARE(o->property("test").toBool(), true);
5450 // Allow an alais to a composite element
5452 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5454 QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
5456 QObject *object = component.create();
5457 QVERIFY(object != 0);
5462 void tst_qdeclarativeecmascript::qtbug_20344()
5464 QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
5466 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5467 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5469 QObject *object = component.create();
5470 QVERIFY(object != 0);
5475 void tst_qdeclarativeecmascript::revisionErrors()
5478 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
5479 QString url = component.url().toString();
5481 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5482 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5483 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5485 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5486 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5487 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5488 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5489 QVERIFY(object != 0);
5493 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
5494 QString url = component.url().toString();
5496 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5497 // method2, prop2 from MyRevisionedClass not available
5498 // method4, prop4 from MyRevisionedSubclass not available
5499 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5500 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5501 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5502 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5503 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5505 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5506 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5507 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5508 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5509 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5510 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5511 QVERIFY(object != 0);
5515 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
5516 QString url = component.url().toString();
5518 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5519 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5520 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5521 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5522 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5523 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5524 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5525 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5526 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5527 QVERIFY(object != 0);
5532 void tst_qdeclarativeecmascript::revision()
5535 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
5536 QString url = component.url().toString();
5538 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5539 QVERIFY(object != 0);
5543 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
5544 QString url = component.url().toString();
5546 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5547 QVERIFY(object != 0);
5551 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
5552 QString url = component.url().toString();
5554 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5555 QVERIFY(object != 0);
5558 // Test that non-root classes can resolve revisioned methods
5560 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
5562 QObject *object = component.create();
5563 QVERIFY(object != 0);
5564 QCOMPARE(object->property("test").toReal(), 11.);
5569 void tst_qdeclarativeecmascript::realToInt()
5571 QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
5572 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5573 QVERIFY(object != 0);
5575 QMetaObject::invokeMethod(object, "test1");
5576 QCOMPARE(object->value(), int(4));
5577 QMetaObject::invokeMethod(object, "test2");
5578 QCOMPARE(object->value(), int(8));
5581 void tst_qdeclarativeecmascript::urlProperty()
5584 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
5585 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5586 QVERIFY(object != 0);
5587 object->setStringProperty("http://qt-project.org");
5588 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5589 QCOMPARE(object->intProperty(), 123);
5590 QCOMPARE(object->value(), 1);
5591 QCOMPARE(object->property("result").toBool(), true);
5595 void tst_qdeclarativeecmascript::urlPropertyWithEncoding()
5598 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.2.qml"));
5599 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5600 QVERIFY(object != 0);
5601 object->setStringProperty("http://qt-project.org");
5603 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5604 QCOMPARE(object->urlProperty(), encoded);
5605 QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
5606 QCOMPARE(object->property("result").toBool(), true);
5610 void tst_qdeclarativeecmascript::urlListPropertyWithEncoding()
5613 QDeclarativeComponent component(&engine, testFileUrl("urlListProperty.qml"));
5614 QObject *object = component.create();
5615 QVERIFY(object != 0);
5616 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
5617 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
5618 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
5619 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
5620 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
5622 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5623 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
5624 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
5625 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5626 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5631 void tst_qdeclarativeecmascript::dynamicString()
5633 QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
5634 QObject *object = component.create();
5635 QVERIFY(object != 0);
5636 QCOMPARE(object->property("stringProperty").toString(),
5637 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5640 void tst_qdeclarativeecmascript::automaticSemicolon()
5642 QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
5643 QObject *object = component.create();
5644 QVERIFY(object != 0);
5647 void tst_qdeclarativeecmascript::unaryExpression()
5649 QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
5650 QObject *object = component.create();
5651 QVERIFY(object != 0);
5654 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5655 void tst_qdeclarativeecmascript::doubleEvaluate()
5657 QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
5658 QObject *object = component.create();
5659 QVERIFY(object != 0);
5660 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5662 QCOMPARE(wc->count(), 1);
5664 wc->setProperty("x", 9);
5666 QCOMPARE(wc->count(), 2);
5671 static QStringList messages;
5672 static void captureMsgHandler(QtMsgType, const char *msg)
5674 messages.append(QLatin1String(msg));
5677 void tst_qdeclarativeecmascript::nonNotifyable()
5679 QV4Compiler::enableV4(false);
5680 QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
5681 QV4Compiler::enableV4(true);
5683 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5685 QObject *object = component.create();
5686 qInstallMsgHandler(old);
5688 QVERIFY(object != 0);
5690 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5691 component.url().toString() +
5692 QLatin1String(":5 depends on non-NOTIFYable properties:");
5693 QString expected2 = QLatin1String(" ") +
5694 QLatin1String(object->metaObject()->className()) +
5695 QLatin1String("::value");
5697 QCOMPARE(messages.length(), 2);
5698 QCOMPARE(messages.at(0), expected1);
5699 QCOMPARE(messages.at(1), expected2);
5704 void tst_qdeclarativeecmascript::forInLoop()
5706 QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
5707 QObject *object = component.create();
5708 QVERIFY(object != 0);
5710 QMetaObject::invokeMethod(object, "listProperty");
5712 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5713 QCOMPARE(r.size(), 3);
5714 QCOMPARE(r[0],QLatin1String("0=obj1"));
5715 QCOMPARE(r[1],QLatin1String("1=obj2"));
5716 QCOMPARE(r[2],QLatin1String("2=obj3"));
5718 //TODO: should test for in loop for other objects (such as QObjects) as well.
5723 // An object the binding depends on is deleted while the binding is still running
5724 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5726 QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
5727 QObject *object = component.create();
5728 QVERIFY(object != 0);
5732 void tst_qdeclarativeecmascript::qtbug_22679()
5735 object.setStringProperty(QLatin1String("Please work correctly"));
5736 engine.rootContext()->setContextProperty("contextProp", &object);
5738 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
5739 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5740 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5742 QObject *o = component.create();
5744 QCOMPARE(warningsSpy.count(), 0);
5748 void tst_qdeclarativeecmascript::qtbug_22843_data()
5750 QTest::addColumn<bool>("library");
5752 QTest::newRow("without .pragma library") << false;
5753 QTest::newRow("with .pragma library") << true;
5756 void tst_qdeclarativeecmascript::qtbug_22843()
5758 QFETCH(bool, library);
5760 QString fileName("qtbug_22843");
5762 fileName += QLatin1String(".library");
5763 fileName += QLatin1String(".qml");
5765 QDeclarativeComponent component(&engine, testFileUrl(fileName));
5766 QString url = component.url().toString();
5767 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5768 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5770 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5771 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5772 for (int x = 0; x < 3; ++x) {
5773 warningsSpy.clear();
5774 // For libraries, only the first import attempt should produce a
5775 // SyntaxError warning; subsequent component creation should not
5776 // attempt to reload the script.
5777 bool expectSyntaxError = !library || (x == 0);
5778 if (expectSyntaxError)
5779 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5780 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5781 QObject *object = component.create();
5782 QVERIFY(object != 0);
5783 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5789 void tst_qdeclarativeecmascript::switchStatement()
5792 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
5793 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5794 QVERIFY(object != 0);
5796 // `object->value()' is the number of executed statements
5798 object->setStringProperty("A");
5799 QCOMPARE(object->value(), 5);
5801 object->setStringProperty("S");
5802 QCOMPARE(object->value(), 3);
5804 object->setStringProperty("D");
5805 QCOMPARE(object->value(), 3);
5807 object->setStringProperty("F");
5808 QCOMPARE(object->value(), 4);
5810 object->setStringProperty("something else");
5811 QCOMPARE(object->value(), 1);
5815 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
5816 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5817 QVERIFY(object != 0);
5819 // `object->value()' is the number of executed statements
5821 object->setStringProperty("A");
5822 QCOMPARE(object->value(), 5);
5824 object->setStringProperty("S");
5825 QCOMPARE(object->value(), 3);
5827 object->setStringProperty("D");
5828 QCOMPARE(object->value(), 3);
5830 object->setStringProperty("F");
5831 QCOMPARE(object->value(), 3);
5833 object->setStringProperty("something else");
5834 QCOMPARE(object->value(), 4);
5838 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
5839 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5840 QVERIFY(object != 0);
5842 // `object->value()' is the number of executed statements
5844 object->setStringProperty("A");
5845 QCOMPARE(object->value(), 5);
5847 object->setStringProperty("S");
5848 QCOMPARE(object->value(), 3);
5850 object->setStringProperty("D");
5851 QCOMPARE(object->value(), 3);
5853 object->setStringProperty("F");
5854 QCOMPARE(object->value(), 3);
5856 object->setStringProperty("something else");
5857 QCOMPARE(object->value(), 6);
5861 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
5863 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5864 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5866 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5867 QVERIFY(object != 0);
5869 // `object->value()' is the number of executed statements
5871 object->setStringProperty("A");
5872 QCOMPARE(object->value(), 5);
5874 object->setStringProperty("S");
5875 QCOMPARE(object->value(), 3);
5877 object->setStringProperty("D");
5878 QCOMPARE(object->value(), 3);
5880 object->setStringProperty("F");
5881 QCOMPARE(object->value(), 3);
5883 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5885 object->setStringProperty("something else");
5889 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
5890 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5891 QVERIFY(object != 0);
5893 // `object->value()' is the number of executed statements
5895 object->setStringProperty("A");
5896 QCOMPARE(object->value(), 1);
5898 object->setStringProperty("S");
5899 QCOMPARE(object->value(), 1);
5901 object->setStringProperty("D");
5902 QCOMPARE(object->value(), 1);
5904 object->setStringProperty("F");
5905 QCOMPARE(object->value(), 1);
5907 object->setStringProperty("something else");
5908 QCOMPARE(object->value(), 1);
5912 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
5913 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5914 QVERIFY(object != 0);
5916 // `object->value()' is the number of executed statements
5918 object->setStringProperty("A");
5919 QCOMPARE(object->value(), 123);
5921 object->setStringProperty("S");
5922 QCOMPARE(object->value(), 123);
5924 object->setStringProperty("D");
5925 QCOMPARE(object->value(), 321);
5927 object->setStringProperty("F");
5928 QCOMPARE(object->value(), 321);
5930 object->setStringProperty("something else");
5931 QCOMPARE(object->value(), 0);
5935 void tst_qdeclarativeecmascript::withStatement()
5938 QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
5939 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5940 QVERIFY(object != 0);
5942 QCOMPARE(object->value(), 123);
5946 void tst_qdeclarativeecmascript::tryStatement()
5949 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
5950 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5951 QVERIFY(object != 0);
5953 QCOMPARE(object->value(), 123);
5957 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
5958 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5959 QVERIFY(object != 0);
5961 QCOMPARE(object->value(), 321);
5965 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
5966 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5967 QVERIFY(object != 0);
5969 QCOMPARE(object->value(), 1);
5973 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
5974 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5975 QVERIFY(object != 0);
5977 QCOMPARE(object->value(), 1);
5981 QTEST_MAIN(tst_qdeclarativeecmascript)
5983 #include "tst_qdeclarativeecmascript.moc"