1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include <private/qdeclarativevmemetaobject_p.h>
53 #include <private/qv4compiler_p.h>
54 #include "testtypes.h"
55 #include "testhttpserver.h"
56 #include "../../shared/util.h"
59 This test covers evaluation of ECMAScript expressions and bindings from within
60 QML. This does not include static QML language issues.
62 Static QML language issues are covered in qmllanguage
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 transientErrors();
117 void shutdownErrors();
118 void compositePropertyType();
120 void undefinedResetsProperty();
121 void listToVariant();
122 void listAssignment();
123 void multiEngineObject();
124 void deletedObject();
125 void attachedPropertyScope();
126 void scriptConnect();
127 void scriptDisconnect();
129 void cppOwnershipReturnValue();
130 void ownershipCustomReturnValue();
131 void qlistqobjectMethods();
132 void strictlyEquals();
134 void numberAssignment();
135 void propertySplicing();
136 void signalWithUnknownTypes();
137 void signalWithJSValueInVariant_data();
138 void signalWithJSValueInVariant();
139 void signalWithJSValueInVariant_twoEngines_data();
140 void signalWithJSValueInVariant_twoEngines();
141 void signalWithQJSValue_data();
142 void signalWithQJSValue();
143 void moduleApi_data();
145 void importScripts_data();
146 void importScripts();
147 void scarceResources();
148 void scarceResources_data();
149 void scarceResources_other();
150 void propertyChangeSlots();
151 void propertyVar_data();
153 void propertyVarCpp();
154 void propertyVarOwnership();
155 void propertyVarImplicitOwnership();
156 void propertyVarReparent();
157 void propertyVarReparentNullContext();
158 void propertyVarCircular();
159 void propertyVarCircular2();
160 void propertyVarInheritance();
161 void propertyVarInheritance2();
162 void elementAssign();
163 void objectPassThroughSignals();
164 void objectConversion();
165 void booleanConversion();
166 void handleReferenceManagement();
168 void readonlyDeclaration();
169 void sequenceConversionRead();
170 void sequenceConversionWrite();
171 void sequenceConversionArray();
172 void sequenceConversionThreads();
173 void sequenceConversionBindings();
174 void sequenceConversionCopy();
175 void assignSequenceTypes();
181 void dynamicCreationCrash();
182 void dynamicCreationOwnership();
184 void nullObjectBinding();
185 void deletedEngine();
186 void libraryScriptAssert();
187 void variantsAssignedUndefined();
189 void qtcreatorbug_1289();
190 void noSpuriousWarningsAtShutdown();
191 void canAssignNullToQObject();
192 void functionAssignment_fromBinding();
193 void functionAssignment_fromJS();
194 void functionAssignment_fromJS_data();
195 void functionAssignmentfromJS_invalid();
202 void qobjectConnectionListExceptionHandling();
203 void nonscriptable();
207 void sharedAttachedObject();
209 void writeRemovesBinding();
210 void aliasBindingsAssignCorrectly();
211 void aliasBindingsOverrideTarget();
212 void aliasWritesOverrideBindings();
213 void aliasToCompositeElement();
216 void urlPropertyWithEncoding();
217 void urlListPropertyWithEncoding();
218 void dynamicString();
220 void signalHandlers();
221 void doubleEvaluate();
223 void nonNotifyable();
224 void deleteWhileBindingRunning();
225 void callQtInvokables();
226 void invokableObjectArg();
227 void invokableObjectRet();
230 void qtbug_22843_data();
232 void revisionErrors();
235 void automaticSemicolon();
236 void unaryExpression();
237 void switchStatement();
238 void withStatement();
242 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
243 QDeclarativeEngine engine;
246 void tst_qdeclarativeecmascript::initTestCase()
248 QDeclarativeDataTest::initTestCase();
252 void tst_qdeclarativeecmascript::assignBasicTypes()
255 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
256 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
257 QVERIFY(object != 0);
258 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
259 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
260 QCOMPARE(object->stringProperty(), QString("Hello World!"));
261 QCOMPARE(object->uintProperty(), uint(10));
262 QCOMPARE(object->intProperty(), -19);
263 QCOMPARE((float)object->realProperty(), float(23.2));
264 QCOMPARE((float)object->doubleProperty(), float(-19.75));
265 QCOMPARE((float)object->floatProperty(), float(8.5));
266 QCOMPARE(object->colorProperty(), QColor("red"));
267 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
268 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
269 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
270 QCOMPARE(object->pointProperty(), QPoint(99,13));
271 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
272 QCOMPARE(object->sizeProperty(), QSize(99, 13));
273 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
274 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
275 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
276 QCOMPARE(object->boolProperty(), true);
277 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
278 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
279 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
283 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
284 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
285 QVERIFY(object != 0);
286 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
287 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
288 QCOMPARE(object->stringProperty(), QString("Hello World!"));
289 QCOMPARE(object->uintProperty(), uint(10));
290 QCOMPARE(object->intProperty(), -19);
291 QCOMPARE((float)object->realProperty(), float(23.2));
292 QCOMPARE((float)object->doubleProperty(), float(-19.75));
293 QCOMPARE((float)object->floatProperty(), float(8.5));
294 QCOMPARE(object->colorProperty(), QColor("red"));
295 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
296 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
297 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
298 QCOMPARE(object->pointProperty(), QPoint(99,13));
299 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
300 QCOMPARE(object->sizeProperty(), QSize(99, 13));
301 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
302 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
303 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
304 QCOMPARE(object->boolProperty(), true);
305 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
306 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
307 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
312 void tst_qdeclarativeecmascript::idShortcutInvalidates()
315 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
316 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
317 QVERIFY(object != 0);
318 QVERIFY(object->objectProperty() != 0);
319 delete object->objectProperty();
320 QVERIFY(object->objectProperty() == 0);
325 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
326 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
327 QVERIFY(object != 0);
328 QVERIFY(object->objectProperty() != 0);
329 delete object->objectProperty();
330 QVERIFY(object->objectProperty() == 0);
335 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
338 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
339 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
340 QVERIFY(object != 0);
341 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
345 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
346 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
347 QVERIFY(object != 0);
348 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
353 void tst_qdeclarativeecmascript::signalAssignment()
356 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
357 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
358 QVERIFY(object != 0);
359 QCOMPARE(object->string(), QString());
360 emit object->basicSignal();
361 QCOMPARE(object->string(), QString("pass"));
366 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
367 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
368 QVERIFY(object != 0);
369 QCOMPARE(object->string(), QString());
370 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
371 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
376 void tst_qdeclarativeecmascript::methods()
379 QDeclarativeComponent component(&engine, testFileUrl("methods.1.qml"));
380 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
381 QVERIFY(object != 0);
382 QCOMPARE(object->methodCalled(), false);
383 QCOMPARE(object->methodIntCalled(), false);
384 emit object->basicSignal();
385 QCOMPARE(object->methodCalled(), true);
386 QCOMPARE(object->methodIntCalled(), false);
391 QDeclarativeComponent component(&engine, testFileUrl("methods.2.qml"));
392 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
393 QVERIFY(object != 0);
394 QCOMPARE(object->methodCalled(), false);
395 QCOMPARE(object->methodIntCalled(), false);
396 emit object->basicSignal();
397 QCOMPARE(object->methodCalled(), false);
398 QCOMPARE(object->methodIntCalled(), true);
403 QDeclarativeComponent component(&engine, testFileUrl("methods.3.qml"));
404 QObject *object = component.create();
405 QVERIFY(object != 0);
406 QCOMPARE(object->property("test").toInt(), 19);
411 QDeclarativeComponent component(&engine, testFileUrl("methods.4.qml"));
412 QObject *object = component.create();
413 QVERIFY(object != 0);
414 QCOMPARE(object->property("test").toInt(), 19);
415 QCOMPARE(object->property("test2").toInt(), 17);
416 QCOMPARE(object->property("test3").toInt(), 16);
421 QDeclarativeComponent component(&engine, testFileUrl("methods.5.qml"));
422 QObject *object = component.create();
423 QVERIFY(object != 0);
424 QCOMPARE(object->property("test").toInt(), 9);
429 void tst_qdeclarativeecmascript::bindingLoop()
431 QDeclarativeComponent component(&engine, testFileUrl("bindingLoop.qml"));
432 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
433 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
434 QObject *object = component.create();
435 QVERIFY(object != 0);
439 void tst_qdeclarativeecmascript::basicExpressions_data()
441 QTest::addColumn<QString>("expression");
442 QTest::addColumn<QVariant>("result");
443 QTest::addColumn<bool>("nest");
445 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
446 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
447 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
448 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
449 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
450 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
451 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
452 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
453 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
454 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
455 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
456 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
457 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
458 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
459 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
460 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
461 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
462 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
463 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
466 void tst_qdeclarativeecmascript::basicExpressions()
468 QFETCH(QString, expression);
469 QFETCH(QVariant, result);
475 MyDefaultObject1 default1;
476 MyDefaultObject3 default3;
477 object1.setStringProperty("Object1");
478 object2.setStringProperty("Object2");
479 object3.setStringProperty("Object3");
481 QDeclarativeContext context(engine.rootContext());
482 QDeclarativeContext nestedContext(&context);
484 context.setContextObject(&default1);
485 context.setContextProperty("a", QVariant(1944));
486 context.setContextProperty("b", QVariant("Milk"));
487 context.setContextProperty("object", &object1);
488 context.setContextProperty("objectOverride", &object2);
489 nestedContext.setContextObject(&default3);
490 nestedContext.setContextProperty("b", QVariant("Cow"));
491 nestedContext.setContextProperty("objectOverride", &object3);
492 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
494 MyExpression expr(nest?&nestedContext:&context, expression);
495 QCOMPARE(expr.evaluate(), result);
498 void tst_qdeclarativeecmascript::arrayExpressions()
504 QDeclarativeContext context(engine.rootContext());
505 context.setContextProperty("a", &obj1);
506 context.setContextProperty("b", &obj2);
507 context.setContextProperty("c", &obj3);
509 MyExpression expr(&context, "[a, b, c, 10]");
510 QVariant result = expr.evaluate();
511 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
512 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
513 QCOMPARE(list.count(), 4);
514 QCOMPARE(list.at(0), &obj1);
515 QCOMPARE(list.at(1), &obj2);
516 QCOMPARE(list.at(2), &obj3);
517 QCOMPARE(list.at(3), (QObject *)0);
520 // Tests that modifying a context property will reevaluate expressions
521 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
523 QDeclarativeContext context(engine.rootContext());
526 MyQmlObject *object3 = new MyQmlObject;
528 object1.setStringProperty("Hello");
529 object2.setStringProperty("World");
531 context.setContextProperty("testProp", QVariant(1));
532 context.setContextProperty("testObj", &object1);
533 context.setContextProperty("testObj2", object3);
536 MyExpression expr(&context, "testProp + 1");
537 QCOMPARE(expr.changed, false);
538 QCOMPARE(expr.evaluate(), QVariant(2));
540 context.setContextProperty("testProp", QVariant(2));
541 QCOMPARE(expr.changed, true);
542 QCOMPARE(expr.evaluate(), QVariant(3));
546 MyExpression expr(&context, "testProp + testProp + testProp");
547 QCOMPARE(expr.changed, false);
548 QCOMPARE(expr.evaluate(), QVariant(6));
550 context.setContextProperty("testProp", QVariant(4));
551 QCOMPARE(expr.changed, true);
552 QCOMPARE(expr.evaluate(), QVariant(12));
556 MyExpression expr(&context, "testObj.stringProperty");
557 QCOMPARE(expr.changed, false);
558 QCOMPARE(expr.evaluate(), QVariant("Hello"));
560 context.setContextProperty("testObj", &object2);
561 QCOMPARE(expr.changed, true);
562 QCOMPARE(expr.evaluate(), QVariant("World"));
566 MyExpression expr(&context, "testObj.stringProperty /**/");
567 QCOMPARE(expr.changed, false);
568 QCOMPARE(expr.evaluate(), QVariant("World"));
570 context.setContextProperty("testObj", &object1);
571 QCOMPARE(expr.changed, true);
572 QCOMPARE(expr.evaluate(), QVariant("Hello"));
576 MyExpression expr(&context, "testObj2");
577 QCOMPARE(expr.changed, false);
578 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
584 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
586 QDeclarativeContext context(engine.rootContext());
590 context.setContextProperty("testObj", &object1);
592 object1.setStringProperty(QLatin1String("Hello"));
593 object2.setStringProperty(QLatin1String("Dog"));
594 object3.setStringProperty(QLatin1String("Cat"));
597 MyExpression expr(&context, "testObj.stringProperty");
598 QCOMPARE(expr.changed, false);
599 QCOMPARE(expr.evaluate(), QVariant("Hello"));
601 object1.setStringProperty(QLatin1String("World"));
602 QCOMPARE(expr.changed, true);
603 QCOMPARE(expr.evaluate(), QVariant("World"));
607 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
608 QCOMPARE(expr.changed, false);
609 QCOMPARE(expr.evaluate(), QVariant());
611 object1.setObjectProperty(&object2);
612 QCOMPARE(expr.changed, true);
613 expr.changed = false;
614 QCOMPARE(expr.evaluate(), QVariant("Dog"));
616 object1.setObjectProperty(&object3);
617 QCOMPARE(expr.changed, true);
618 expr.changed = false;
619 QCOMPARE(expr.evaluate(), QVariant("Cat"));
621 object1.setObjectProperty(0);
622 QCOMPARE(expr.changed, true);
623 expr.changed = false;
624 QCOMPARE(expr.evaluate(), QVariant());
626 object1.setObjectProperty(&object3);
627 QCOMPARE(expr.changed, true);
628 expr.changed = false;
629 QCOMPARE(expr.evaluate(), QVariant("Cat"));
631 object3.setStringProperty("Donkey");
632 QCOMPARE(expr.changed, true);
633 expr.changed = false;
634 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
638 void tst_qdeclarativeecmascript::deferredProperties()
640 QDeclarativeComponent component(&engine, testFileUrl("deferredProperties.qml"));
641 MyDeferredObject *object =
642 qobject_cast<MyDeferredObject *>(component.create());
643 QVERIFY(object != 0);
644 QCOMPARE(object->value(), 0);
645 QVERIFY(object->objectProperty() == 0);
646 QVERIFY(object->objectProperty2() != 0);
647 qmlExecuteDeferred(object);
648 QCOMPARE(object->value(), 10);
649 QVERIFY(object->objectProperty() != 0);
650 MyQmlObject *qmlObject =
651 qobject_cast<MyQmlObject *>(object->objectProperty());
652 QVERIFY(qmlObject != 0);
653 QCOMPARE(qmlObject->value(), 10);
654 object->setValue(19);
655 QCOMPARE(qmlObject->value(), 19);
660 // Check errors on deferred properties are correctly emitted
661 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
663 QDeclarativeComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
664 MyDeferredObject *object =
665 qobject_cast<MyDeferredObject *>(component.create());
666 QVERIFY(object != 0);
667 QCOMPARE(object->value(), 0);
668 QVERIFY(object->objectProperty() == 0);
669 QVERIFY(object->objectProperty2() == 0);
671 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
672 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
674 qmlExecuteDeferred(object);
679 void tst_qdeclarativeecmascript::extensionObjects()
681 QDeclarativeComponent component(&engine, testFileUrl("extensionObjects.qml"));
682 MyExtendedObject *object =
683 qobject_cast<MyExtendedObject *>(component.create());
684 QVERIFY(object != 0);
685 QCOMPARE(object->baseProperty(), 13);
686 QCOMPARE(object->coreProperty(), 9);
687 object->setProperty("extendedProperty", QVariant(11));
688 object->setProperty("baseExtendedProperty", QVariant(92));
689 QCOMPARE(object->coreProperty(), 11);
690 QCOMPARE(object->baseProperty(), 92);
692 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
694 QCOMPARE(nested->baseProperty(), 13);
695 QCOMPARE(nested->coreProperty(), 9);
696 nested->setProperty("extendedProperty", QVariant(11));
697 nested->setProperty("baseExtendedProperty", QVariant(92));
698 QCOMPARE(nested->coreProperty(), 11);
699 QCOMPARE(nested->baseProperty(), 92);
704 void tst_qdeclarativeecmascript::overrideExtensionProperties()
706 QDeclarativeComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
707 OverrideDefaultPropertyObject *object =
708 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
709 QVERIFY(object != 0);
710 QVERIFY(object->secondProperty() != 0);
711 QVERIFY(object->firstProperty() == 0);
716 void tst_qdeclarativeecmascript::attachedProperties()
719 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.qml"));
720 QObject *object = component.create();
721 QVERIFY(object != 0);
722 QCOMPARE(object->property("a").toInt(), 19);
723 QCOMPARE(object->property("b").toInt(), 19);
724 QCOMPARE(object->property("c").toInt(), 19);
725 QCOMPARE(object->property("d").toInt(), 19);
730 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
731 QObject *object = component.create();
732 QVERIFY(object != 0);
733 QCOMPARE(object->property("a").toInt(), 26);
734 QCOMPARE(object->property("b").toInt(), 26);
735 QCOMPARE(object->property("c").toInt(), 26);
736 QCOMPARE(object->property("d").toInt(), 26);
742 QDeclarativeComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
743 QObject *object = component.create();
744 QVERIFY(object != 0);
746 QMetaObject::invokeMethod(object, "writeValue2");
748 MyQmlAttachedObject *attached =
749 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
750 QVERIFY(attached != 0);
752 QCOMPARE(attached->value2(), 9);
757 void tst_qdeclarativeecmascript::enums()
761 QDeclarativeComponent component(&engine, testFileUrl("enums.1.qml"));
762 QObject *object = component.create();
763 QVERIFY(object != 0);
765 QCOMPARE(object->property("a").toInt(), 0);
766 QCOMPARE(object->property("b").toInt(), 1);
767 QCOMPARE(object->property("c").toInt(), 2);
768 QCOMPARE(object->property("d").toInt(), 3);
769 QCOMPARE(object->property("e").toInt(), 0);
770 QCOMPARE(object->property("f").toInt(), 1);
771 QCOMPARE(object->property("g").toInt(), 2);
772 QCOMPARE(object->property("h").toInt(), 3);
773 QCOMPARE(object->property("i").toInt(), 19);
774 QCOMPARE(object->property("j").toInt(), 19);
778 // Non-existent enums
780 QDeclarativeComponent component(&engine, testFileUrl("enums.2.qml"));
782 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
783 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
784 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
785 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
787 QObject *object = component.create();
788 QVERIFY(object != 0);
789 QCOMPARE(object->property("a").toInt(), 0);
790 QCOMPARE(object->property("b").toInt(), 0);
796 void tst_qdeclarativeecmascript::valueTypeFunctions()
798 QDeclarativeComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
799 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
801 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
802 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
808 Tests that writing a constant to a property with a binding on it disables the
811 void tst_qdeclarativeecmascript::constantsOverrideBindings()
815 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
816 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
817 QVERIFY(object != 0);
819 QCOMPARE(object->property("c2").toInt(), 0);
820 object->setProperty("c1", QVariant(9));
821 QCOMPARE(object->property("c2").toInt(), 9);
823 emit object->basicSignal();
825 QCOMPARE(object->property("c2").toInt(), 13);
826 object->setProperty("c1", QVariant(8));
827 QCOMPARE(object->property("c2").toInt(), 13);
832 // During construction
834 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
835 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
836 QVERIFY(object != 0);
838 QCOMPARE(object->property("c1").toInt(), 0);
839 QCOMPARE(object->property("c2").toInt(), 10);
840 object->setProperty("c1", QVariant(9));
841 QCOMPARE(object->property("c1").toInt(), 9);
842 QCOMPARE(object->property("c2").toInt(), 10);
850 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.3.qml"));
851 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
852 QVERIFY(object != 0);
854 QCOMPARE(object->property("c2").toInt(), 0);
855 object->setProperty("c1", QVariant(9));
856 QCOMPARE(object->property("c2").toInt(), 9);
858 object->setProperty("c2", QVariant(13));
859 QCOMPARE(object->property("c2").toInt(), 13);
860 object->setProperty("c1", QVariant(7));
861 QCOMPARE(object->property("c1").toInt(), 7);
862 QCOMPARE(object->property("c2").toInt(), 13);
870 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
871 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
872 QVERIFY(object != 0);
874 QCOMPARE(object->property("c1").toInt(), 0);
875 QCOMPARE(object->property("c3").toInt(), 10);
876 object->setProperty("c1", QVariant(9));
877 QCOMPARE(object->property("c1").toInt(), 9);
878 QCOMPARE(object->property("c3").toInt(), 10);
885 Tests that assigning a binding to a property that already has a binding causes
886 the original binding to be disabled.
888 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
890 QDeclarativeComponent component(&engine,
891 testFileUrl("outerBindingOverridesInnerBinding.qml"));
892 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
893 QVERIFY(object != 0);
895 QCOMPARE(object->property("c1").toInt(), 0);
896 QCOMPARE(object->property("c2").toInt(), 0);
897 QCOMPARE(object->property("c3").toInt(), 0);
899 object->setProperty("c1", QVariant(9));
900 QCOMPARE(object->property("c1").toInt(), 9);
901 QCOMPARE(object->property("c2").toInt(), 0);
902 QCOMPARE(object->property("c3").toInt(), 0);
904 object->setProperty("c3", QVariant(8));
905 QCOMPARE(object->property("c1").toInt(), 9);
906 QCOMPARE(object->property("c2").toInt(), 8);
907 QCOMPARE(object->property("c3").toInt(), 8);
913 Access a non-existent attached object.
915 Tests for a regression where this used to crash.
917 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
919 QDeclarativeComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
921 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
922 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
924 QObject *object = component.create();
925 QVERIFY(object != 0);
930 void tst_qdeclarativeecmascript::scope()
933 QDeclarativeComponent component(&engine, testFileUrl("scope.qml"));
934 QObject *object = component.create();
935 QVERIFY(object != 0);
937 QCOMPARE(object->property("test1").toInt(), 1);
938 QCOMPARE(object->property("test2").toInt(), 2);
939 QCOMPARE(object->property("test3").toString(), QString("1Test"));
940 QCOMPARE(object->property("test4").toString(), QString("2Test"));
941 QCOMPARE(object->property("test5").toInt(), 1);
942 QCOMPARE(object->property("test6").toInt(), 1);
943 QCOMPARE(object->property("test7").toInt(), 2);
944 QCOMPARE(object->property("test8").toInt(), 2);
945 QCOMPARE(object->property("test9").toInt(), 1);
946 QCOMPARE(object->property("test10").toInt(), 3);
952 QDeclarativeComponent component(&engine, testFileUrl("scope.2.qml"));
953 QObject *object = component.create();
954 QVERIFY(object != 0);
956 QCOMPARE(object->property("test1").toInt(), 19);
957 QCOMPARE(object->property("test2").toInt(), 19);
958 QCOMPARE(object->property("test3").toInt(), 14);
959 QCOMPARE(object->property("test4").toInt(), 14);
960 QCOMPARE(object->property("test5").toInt(), 24);
961 QCOMPARE(object->property("test6").toInt(), 24);
967 QDeclarativeComponent component(&engine, testFileUrl("scope.3.qml"));
968 QObject *object = component.create();
969 QVERIFY(object != 0);
971 QCOMPARE(object->property("test1").toBool(), true);
972 QCOMPARE(object->property("test2").toBool(), true);
973 QCOMPARE(object->property("test3").toBool(), true);
978 // Signal argument scope
980 QDeclarativeComponent component(&engine, testFileUrl("scope.4.qml"));
981 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
982 QVERIFY(object != 0);
984 QCOMPARE(object->property("test").toInt(), 0);
985 QCOMPARE(object->property("test2").toString(), QString());
987 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
989 QCOMPARE(object->property("test").toInt(), 13);
990 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
996 QDeclarativeComponent component(&engine, testFileUrl("scope.5.qml"));
997 QObject *object = component.create();
998 QVERIFY(object != 0);
1000 QCOMPARE(object->property("test1").toBool(), true);
1001 QCOMPARE(object->property("test2").toBool(), true);
1007 QDeclarativeComponent component(&engine, testFileUrl("scope.6.qml"));
1008 QObject *object = component.create();
1009 QVERIFY(object != 0);
1011 QCOMPARE(object->property("test").toBool(), true);
1017 // In 4.7, non-library javascript files that had no imports shared the imports of their
1018 // importing context
1019 void tst_qdeclarativeecmascript::importScope()
1021 QDeclarativeComponent component(&engine, testFileUrl("importScope.qml"));
1022 QObject *o = component.create();
1025 QCOMPARE(o->property("test").toInt(), 240);
1031 Tests that "any" type passes through a synthesized signal parameter. This
1032 is essentially a test of QDeclarativeMetaType::copy()
1034 void tst_qdeclarativeecmascript::signalParameterTypes()
1036 QDeclarativeComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
1037 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1038 QVERIFY(object != 0);
1040 emit object->basicSignal();
1042 QCOMPARE(object->property("intProperty").toInt(), 10);
1043 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1044 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1045 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1046 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1047 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1053 Test that two JS objects for the same QObject compare as equal.
1055 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1057 QDeclarativeComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
1058 QObject *object = component.create();
1059 QVERIFY(object != 0);
1061 QCOMPARE(object->property("test1").toBool(), true);
1062 QCOMPARE(object->property("test2").toBool(), true);
1063 QCOMPARE(object->property("test3").toBool(), true);
1064 QCOMPARE(object->property("test4").toBool(), true);
1065 QCOMPARE(object->property("test5").toBool(), true);
1071 Confirm bindings and alias properties can coexist.
1073 Tests for a regression where the binding would not reevaluate.
1075 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1077 QDeclarativeComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
1078 QObject *object = component.create();
1079 QVERIFY(object != 0);
1081 QCOMPARE(object->property("c2").toInt(), 3);
1082 QCOMPARE(object->property("c3").toInt(), 3);
1084 object->setProperty("c2", QVariant(19));
1086 QCOMPARE(object->property("c2").toInt(), 19);
1087 QCOMPARE(object->property("c3").toInt(), 19);
1093 Ensure that we can write undefined value to an alias property,
1094 and that the aliased property is reset correctly if possible.
1096 void tst_qdeclarativeecmascript::aliasPropertyReset()
1098 QObject *object = 0;
1100 // test that a manual write (of undefined) to a resettable aliased property succeeds
1101 QDeclarativeComponent c1(&engine, testFileUrl("aliasreset/aliasPropertyReset.1.qml"));
1102 object = c1.create();
1103 QVERIFY(object != 0);
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1105 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1106 QMetaObject::invokeMethod(object, "resetAliased");
1107 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1108 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1111 // test that a manual write (of undefined) to a resettable alias property succeeds
1112 QDeclarativeComponent c2(&engine, testFileUrl("aliasreset/aliasPropertyReset.2.qml"));
1113 object = c2.create();
1114 QVERIFY(object != 0);
1115 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1116 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1117 QMetaObject::invokeMethod(object, "resetAlias");
1118 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1119 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1122 // test that an alias to a bound property works correctly
1123 QDeclarativeComponent c3(&engine, testFileUrl("aliasreset/aliasPropertyReset.3.qml"));
1124 object = c3.create();
1125 QVERIFY(object != 0);
1126 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1127 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1128 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1129 QMetaObject::invokeMethod(object, "resetAlias");
1130 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1131 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1132 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1135 // test that a manual write (of undefined) to a resettable alias property
1136 // whose aliased property's object has been deleted, does not crash.
1137 QDeclarativeComponent c4(&engine, testFileUrl("aliasreset/aliasPropertyReset.4.qml"));
1138 object = c4.create();
1139 QVERIFY(object != 0);
1140 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1141 QObject *loader = object->findChild<QObject*>("loader");
1142 QVERIFY(loader != 0);
1144 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1145 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1146 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1147 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1148 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1151 // test that binding an alias property to an undefined value works correctly
1152 QDeclarativeComponent c5(&engine, testFileUrl("aliasreset/aliasPropertyReset.5.qml"));
1153 object = c5.create();
1154 QVERIFY(object != 0);
1155 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1158 // test that a manual write (of undefined) to a non-resettable property fails properly
1159 QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
1160 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1161 QDeclarativeComponent e1(&engine, url);
1162 object = e1.create();
1163 QVERIFY(object != 0);
1164 QCOMPARE(object->property("intAlias").value<int>(), 12);
1165 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1166 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1167 QMetaObject::invokeMethod(object, "resetAlias");
1168 QCOMPARE(object->property("intAlias").value<int>(), 12);
1169 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1173 void tst_qdeclarativeecmascript::dynamicCreation_data()
1175 QTest::addColumn<QString>("method");
1176 QTest::addColumn<QString>("createdName");
1178 QTest::newRow("One") << "createOne" << "objectOne";
1179 QTest::newRow("Two") << "createTwo" << "objectTwo";
1180 QTest::newRow("Three") << "createThree" << "objectThree";
1184 Test using createQmlObject to dynamically generate an item
1185 Also using createComponent is tested.
1187 void tst_qdeclarativeecmascript::dynamicCreation()
1189 QFETCH(QString, method);
1190 QFETCH(QString, createdName);
1192 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1193 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1194 QVERIFY(object != 0);
1196 QMetaObject::invokeMethod(object, method.toUtf8());
1197 QObject *created = object->objectProperty();
1199 QCOMPARE(created->objectName(), createdName);
1205 Tests the destroy function
1207 void tst_qdeclarativeecmascript::dynamicDestruction()
1210 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
1211 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1212 QVERIFY(object != 0);
1213 QDeclarativeGuard<QObject> createdQmlObject = 0;
1215 QMetaObject::invokeMethod(object, "create");
1216 createdQmlObject = object->objectProperty();
1217 QVERIFY(createdQmlObject);
1218 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1220 QMetaObject::invokeMethod(object, "killOther");
1221 QVERIFY(createdQmlObject);
1223 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1224 QCoreApplication::processEvents();
1225 QVERIFY(createdQmlObject);
1226 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1227 if (createdQmlObject) {
1229 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1230 QCoreApplication::processEvents();
1233 QVERIFY(!createdQmlObject);
1235 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1236 QMetaObject::invokeMethod(object, "killMe");
1238 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1239 QCoreApplication::processEvents();
1244 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
1245 QObject *o = component.create();
1248 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1250 QMetaObject::invokeMethod(o, "create");
1252 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1254 QMetaObject::invokeMethod(o, "destroy");
1256 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1257 QCoreApplication::processEvents();
1259 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1266 tests that id.toString() works
1268 void tst_qdeclarativeecmascript::objectToString()
1270 QDeclarativeComponent component(&engine, testFileUrl("declarativeToString.qml"));
1271 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1272 QVERIFY(object != 0);
1273 QMetaObject::invokeMethod(object, "testToString");
1274 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1275 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1281 tests that id.hasOwnProperty() works
1283 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1285 QUrl url = testFileUrl("declarativeHasOwnProperty.qml");
1286 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1287 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1288 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1290 QDeclarativeComponent component(&engine, url);
1291 QObject *object = component.create();
1292 QVERIFY(object != 0);
1294 // test QObjects in QML
1295 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1296 QVERIFY(object->property("result").value<bool>() == true);
1297 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1298 QVERIFY(object->property("result").value<bool>() == false);
1300 // now test other types in QML
1301 QObject *child = object->findChild<QObject*>("typeObj");
1302 QVERIFY(child != 0);
1303 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1304 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1305 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1306 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1307 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1308 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1309 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1310 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1311 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1312 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1313 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1314 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1316 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1317 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1318 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1319 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1320 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1321 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1322 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1323 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1324 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1330 Tests bindings that indirectly cause their own deletion work.
1332 This test is best run under valgrind to ensure no invalid memory access occur.
1334 void tst_qdeclarativeecmascript::selfDeletingBinding()
1337 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
1338 QObject *object = component.create();
1339 QVERIFY(object != 0);
1340 object->setProperty("triggerDelete", true);
1345 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
1346 QObject *object = component.create();
1347 QVERIFY(object != 0);
1348 object->setProperty("triggerDelete", true);
1354 Test that extended object properties can be accessed.
1356 This test a regression where this used to crash. The issue was specificially
1357 for extended objects that did not include a synthesized meta object (so non-root
1358 and no synthesiszed properties).
1360 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1362 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
1363 QObject *object = component.create();
1364 QVERIFY(object != 0);
1369 Test that extended object properties can be accessed correctly.
1371 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
1373 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
1374 QObject *object = component.create();
1375 QVERIFY(object != 0);
1377 QVariant returnValue;
1378 QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
1379 QCOMPARE(returnValue.toInt(), 42);
1384 Test file/lineNumbers for binding/Script errors.
1386 void tst_qdeclarativeecmascript::scriptErrors()
1388 QDeclarativeComponent component(&engine, testFileUrl("scriptErrors.qml"));
1389 QString url = component.url().toString();
1391 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1392 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1393 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1394 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1395 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1396 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1397 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1398 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1400 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1401 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1402 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1403 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1404 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1405 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1406 QVERIFY(object != 0);
1408 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1409 emit object->basicSignal();
1411 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1412 emit object->anotherBasicSignal();
1414 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1415 emit object->thirdBasicSignal();
1421 Test file/lineNumbers for inline functions.
1423 void tst_qdeclarativeecmascript::functionErrors()
1425 QDeclarativeComponent component(&engine, testFileUrl("functionErrors.qml"));
1426 QString url = component.url().toString();
1428 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1430 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1432 QObject *object = component.create();
1433 QVERIFY(object != 0);
1436 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1437 QDeclarativeComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
1438 url = componentTwo.url().toString();
1439 object = componentTwo.create();
1440 QVERIFY(object != 0);
1442 QString srpname = object->property("srp_name").toString();
1444 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1445 + QLatin1String(" is not a function");
1446 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1447 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1452 Test various errors that can occur when assigning a property from script
1454 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1456 QDeclarativeComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
1458 QString url = component.url().toString();
1460 QObject *object = component.create();
1461 QVERIFY(object != 0);
1463 QCOMPARE(object->property("test1").toBool(), true);
1464 QCOMPARE(object->property("test2").toBool(), true);
1470 Test bindings still work when the reeval is triggered from within
1473 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1475 QDeclarativeComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
1476 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1477 QVERIFY(object != 0);
1479 QCOMPARE(object->property("base").toReal(), 50.);
1480 QCOMPARE(object->property("test1").toReal(), 50.);
1481 QCOMPARE(object->property("test2").toReal(), 50.);
1483 object->basicSignal();
1485 QCOMPARE(object->property("base").toReal(), 200.);
1486 QCOMPARE(object->property("test1").toReal(), 200.);
1487 QCOMPARE(object->property("test2").toReal(), 200.);
1489 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1491 QCOMPARE(object->property("base").toReal(), 400.);
1492 QCOMPARE(object->property("test1").toReal(), 400.);
1493 QCOMPARE(object->property("test2").toReal(), 400.);
1499 Test that list properties can be iterated from ECMAScript
1501 void tst_qdeclarativeecmascript::listProperties()
1503 QDeclarativeComponent component(&engine, testFileUrl("listProperties.qml"));
1504 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1505 QVERIFY(object != 0);
1507 QCOMPARE(object->property("test1").toInt(), 21);
1508 QCOMPARE(object->property("test2").toInt(), 2);
1509 QCOMPARE(object->property("test3").toBool(), true);
1510 QCOMPARE(object->property("test4").toBool(), true);
1515 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1517 QDeclarativeComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
1518 QString url = component.url().toString();
1520 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1522 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1523 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1524 QVERIFY(object != 0);
1526 QCOMPARE(object->property("test").toBool(), false);
1528 MyQmlObject object2;
1529 MyQmlObject object3;
1530 object2.setObjectProperty(&object3);
1531 object->setObjectProperty(&object2);
1533 QCOMPARE(object->property("test").toBool(), true);
1538 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1540 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
1541 QString url = component.url().toString();
1543 QString warning = component.url().toString() + ":6: Error: JS exception";
1545 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1546 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1547 QVERIFY(object != 0);
1551 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1553 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
1554 QString url = component.url().toString();
1556 QString warning = component.url().toString() + ":5: Error: JS exception";
1558 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1559 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1560 QVERIFY(object != 0);
1564 static int transientErrorsMsgCount = 0;
1565 static void transientErrorsMsgHandler(QtMsgType, const char *)
1567 ++transientErrorsMsgCount;
1570 // Check that transient binding errors are not displayed
1571 void tst_qdeclarativeecmascript::transientErrors()
1574 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
1576 transientErrorsMsgCount = 0;
1577 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1579 QObject *object = component.create();
1580 QVERIFY(object != 0);
1582 qInstallMsgHandler(old);
1584 QCOMPARE(transientErrorsMsgCount, 0);
1589 // One binding erroring multiple times, but then resolving
1591 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
1593 transientErrorsMsgCount = 0;
1594 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1596 QObject *object = component.create();
1597 QVERIFY(object != 0);
1599 qInstallMsgHandler(old);
1601 QCOMPARE(transientErrorsMsgCount, 0);
1607 // Check that errors during shutdown are minimized
1608 void tst_qdeclarativeecmascript::shutdownErrors()
1610 QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
1611 QObject *object = component.create();
1612 QVERIFY(object != 0);
1614 transientErrorsMsgCount = 0;
1615 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1619 qInstallMsgHandler(old);
1620 QCOMPARE(transientErrorsMsgCount, 0);
1623 void tst_qdeclarativeecmascript::compositePropertyType()
1625 QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
1627 QTest::ignoreMessage(QtDebugMsg, "hello world");
1628 QObject *object = qobject_cast<QObject *>(component.create());
1633 void tst_qdeclarativeecmascript::jsObject()
1635 QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
1636 QObject *object = component.create();
1637 QVERIFY(object != 0);
1639 QCOMPARE(object->property("test").toInt(), 92);
1644 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1647 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
1648 QObject *object = component.create();
1649 QVERIFY(object != 0);
1651 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1653 object->setProperty("setUndefined", true);
1655 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1657 object->setProperty("setUndefined", false);
1659 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1664 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
1665 QObject *object = component.create();
1666 QVERIFY(object != 0);
1668 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1670 QMetaObject::invokeMethod(object, "doReset");
1672 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1678 // Aliases to variant properties should work
1679 void tst_qdeclarativeecmascript::qtbug_22464()
1681 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
1682 QObject *object = component.create();
1683 QVERIFY(object != 0);
1685 QCOMPARE(object->property("test").toBool(), true);
1690 void tst_qdeclarativeecmascript::qtbug_21580()
1692 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
1694 QObject *object = component.create();
1695 QVERIFY(object != 0);
1697 QCOMPARE(object->property("test").toBool(), true);
1703 void tst_qdeclarativeecmascript::bug1()
1705 QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
1706 QObject *object = component.create();
1707 QVERIFY(object != 0);
1709 QCOMPARE(object->property("test").toInt(), 14);
1711 object->setProperty("a", 11);
1713 QCOMPARE(object->property("test").toInt(), 3);
1715 object->setProperty("b", true);
1717 QCOMPARE(object->property("test").toInt(), 9);
1722 void tst_qdeclarativeecmascript::bug2()
1724 QDeclarativeComponent component(&engine);
1725 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1727 QObject *object = component.create();
1728 QVERIFY(object != 0);
1733 // Don't crash in createObject when the component has errors.
1734 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1736 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1737 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1738 QVERIFY(object != 0);
1740 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1741 QMetaObject::invokeMethod(object, "dontCrash");
1742 QObject *created = object->objectProperty();
1743 QVERIFY(created == 0);
1748 // ownership transferred to JS, ensure that GC runs the dtor
1749 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1752 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1754 // allow the engine to go out of scope too.
1756 QDeclarativeEngine dcoEngine;
1757 QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
1758 QObject *object = component.create();
1759 QVERIFY(object != 0);
1760 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1761 QVERIFY(mdcdo != 0);
1762 mdcdo->setDtorCount(&dtorCount);
1764 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1765 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1767 // we do this once manually, but it should be done automatically
1768 // when the engine goes out of scope (since it should gc in dtor)
1769 QMetaObject::invokeMethod(object, "performGc");
1772 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1773 QCoreApplication::processEvents();
1779 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1780 QCoreApplication::processEvents();
1781 QCOMPARE(dtorCount, expectedDtorCount);
1784 void tst_qdeclarativeecmascript::regExpBug()
1788 QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
1789 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1790 QVERIFY(object != 0);
1791 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1797 QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
1798 QDeclarativeComponent component(&engine, testFileUrl("regExp.2.qml"));
1799 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1800 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1802 QCOMPARE(component.errorString(), err);
1806 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1808 QString functionSource = QLatin1String("(function(object) { return ") +
1809 QLatin1String(source) + QLatin1String(" })");
1811 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1814 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1815 if (function.IsEmpty())
1817 v8::Handle<v8::Value> args[] = { o };
1818 function->Call(engine->global(), 1, args);
1819 return tc.HasCaught();
1822 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1823 const char *source, v8::Handle<v8::Value> result)
1825 QString functionSource = QLatin1String("(function(object) { return ") +
1826 QLatin1String(source) + QLatin1String(" })");
1828 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1831 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1832 if (function.IsEmpty())
1834 v8::Handle<v8::Value> args[] = { o };
1836 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1841 return value->StrictEquals(result);
1844 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1847 QString functionSource = QLatin1String("(function(object) { return ") +
1848 QLatin1String(source) + QLatin1String(" })");
1850 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1852 return v8::Handle<v8::Value>();
1853 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1854 if (function.IsEmpty())
1855 return v8::Handle<v8::Value>();
1856 v8::Handle<v8::Value> args[] = { o };
1858 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1861 return v8::Handle<v8::Value>();
1865 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1866 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1867 #define EVALUATE(source) evaluate(engine, object, source)
1869 void tst_qdeclarativeecmascript::callQtInvokables()
1871 MyInvokableObject o;
1873 QDeclarativeEngine qmlengine;
1874 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1876 QV8Engine *engine = ep->v8engine();
1878 v8::HandleScope handle_scope;
1879 v8::Context::Scope scope(engine->context());
1881 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1883 // Non-existent methods
1885 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1886 QCOMPARE(o.error(), false);
1887 QCOMPARE(o.invoked(), -1);
1888 QCOMPARE(o.actuals().count(), 0);
1891 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1892 QCOMPARE(o.error(), false);
1893 QCOMPARE(o.invoked(), -1);
1894 QCOMPARE(o.actuals().count(), 0);
1896 // Insufficient arguments
1898 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1899 QCOMPARE(o.error(), false);
1900 QCOMPARE(o.invoked(), -1);
1901 QCOMPARE(o.actuals().count(), 0);
1904 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1905 QCOMPARE(o.error(), false);
1906 QCOMPARE(o.invoked(), -1);
1907 QCOMPARE(o.actuals().count(), 0);
1909 // Excessive arguments
1911 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1912 QCOMPARE(o.error(), false);
1913 QCOMPARE(o.invoked(), 8);
1914 QCOMPARE(o.actuals().count(), 1);
1915 QCOMPARE(o.actuals().at(0), QVariant(10));
1918 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1919 QCOMPARE(o.error(), false);
1920 QCOMPARE(o.invoked(), 9);
1921 QCOMPARE(o.actuals().count(), 2);
1922 QCOMPARE(o.actuals().at(0), QVariant(10));
1923 QCOMPARE(o.actuals().at(1), QVariant(11));
1925 // Test return types
1927 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1928 QCOMPARE(o.error(), false);
1929 QCOMPARE(o.invoked(), 0);
1930 QCOMPARE(o.actuals().count(), 0);
1933 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1934 QCOMPARE(o.error(), false);
1935 QCOMPARE(o.invoked(), 1);
1936 QCOMPARE(o.actuals().count(), 0);
1939 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1940 QCOMPARE(o.error(), false);
1941 QCOMPARE(o.invoked(), 2);
1942 QCOMPARE(o.actuals().count(), 0);
1946 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1947 QVERIFY(!ret.IsEmpty());
1948 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1949 QCOMPARE(o.error(), false);
1950 QCOMPARE(o.invoked(), 3);
1951 QCOMPARE(o.actuals().count(), 0);
1956 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1957 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1958 QCOMPARE(o.error(), false);
1959 QCOMPARE(o.invoked(), 4);
1960 QCOMPARE(o.actuals().count(), 0);
1964 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1965 QCOMPARE(o.error(), false);
1966 QCOMPARE(o.invoked(), 5);
1967 QCOMPARE(o.actuals().count(), 0);
1971 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1972 QVERIFY(ret->IsString());
1973 QCOMPARE(engine->toString(ret), QString("Hello world"));
1974 QCOMPARE(o.error(), false);
1975 QCOMPARE(o.invoked(), 6);
1976 QCOMPARE(o.actuals().count(), 0);
1980 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1981 QCOMPARE(o.error(), false);
1982 QCOMPARE(o.invoked(), 7);
1983 QCOMPARE(o.actuals().count(), 0);
1987 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1988 QCOMPARE(o.error(), false);
1989 QCOMPARE(o.invoked(), 8);
1990 QCOMPARE(o.actuals().count(), 1);
1991 QCOMPARE(o.actuals().at(0), QVariant(94));
1994 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1995 QCOMPARE(o.error(), false);
1996 QCOMPARE(o.invoked(), 8);
1997 QCOMPARE(o.actuals().count(), 1);
1998 QCOMPARE(o.actuals().at(0), QVariant(94));
2001 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
2002 QCOMPARE(o.error(), false);
2003 QCOMPARE(o.invoked(), 8);
2004 QCOMPARE(o.actuals().count(), 1);
2005 QCOMPARE(o.actuals().at(0), QVariant(0));
2008 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
2009 QCOMPARE(o.error(), false);
2010 QCOMPARE(o.invoked(), 8);
2011 QCOMPARE(o.actuals().count(), 1);
2012 QCOMPARE(o.actuals().at(0), QVariant(0));
2015 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
2016 QCOMPARE(o.error(), false);
2017 QCOMPARE(o.invoked(), 8);
2018 QCOMPARE(o.actuals().count(), 1);
2019 QCOMPARE(o.actuals().at(0), QVariant(0));
2022 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2023 QCOMPARE(o.error(), false);
2024 QCOMPARE(o.invoked(), 8);
2025 QCOMPARE(o.actuals().count(), 1);
2026 QCOMPARE(o.actuals().at(0), QVariant(0));
2029 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2030 QCOMPARE(o.error(), false);
2031 QCOMPARE(o.invoked(), 9);
2032 QCOMPARE(o.actuals().count(), 2);
2033 QCOMPARE(o.actuals().at(0), QVariant(122));
2034 QCOMPARE(o.actuals().at(1), QVariant(9));
2037 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2038 QCOMPARE(o.error(), false);
2039 QCOMPARE(o.invoked(), 10);
2040 QCOMPARE(o.actuals().count(), 1);
2041 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2044 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2045 QCOMPARE(o.error(), false);
2046 QCOMPARE(o.invoked(), 10);
2047 QCOMPARE(o.actuals().count(), 1);
2048 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2051 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2052 QCOMPARE(o.error(), false);
2053 QCOMPARE(o.invoked(), 10);
2054 QCOMPARE(o.actuals().count(), 1);
2055 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2058 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2059 QCOMPARE(o.error(), false);
2060 QCOMPARE(o.invoked(), 10);
2061 QCOMPARE(o.actuals().count(), 1);
2062 QCOMPARE(o.actuals().at(0), QVariant(0));
2065 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2066 QCOMPARE(o.error(), false);
2067 QCOMPARE(o.invoked(), 10);
2068 QCOMPARE(o.actuals().count(), 1);
2069 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2072 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2073 QCOMPARE(o.error(), false);
2074 QCOMPARE(o.invoked(), 10);
2075 QCOMPARE(o.actuals().count(), 1);
2076 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2079 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2080 QCOMPARE(o.error(), false);
2081 QCOMPARE(o.invoked(), 11);
2082 QCOMPARE(o.actuals().count(), 1);
2083 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2086 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2087 QCOMPARE(o.error(), false);
2088 QCOMPARE(o.invoked(), 11);
2089 QCOMPARE(o.actuals().count(), 1);
2090 QCOMPARE(o.actuals().at(0), QVariant("19"));
2094 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2095 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2096 QCOMPARE(o.error(), false);
2097 QCOMPARE(o.invoked(), 11);
2098 QCOMPARE(o.actuals().count(), 1);
2099 QCOMPARE(o.actuals().at(0), QVariant(expected));
2103 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2104 QCOMPARE(o.error(), false);
2105 QCOMPARE(o.invoked(), 11);
2106 QCOMPARE(o.actuals().count(), 1);
2107 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2110 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2111 QCOMPARE(o.error(), false);
2112 QCOMPARE(o.invoked(), 11);
2113 QCOMPARE(o.actuals().count(), 1);
2114 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2117 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2118 QCOMPARE(o.error(), false);
2119 QCOMPARE(o.invoked(), 12);
2120 QCOMPARE(o.actuals().count(), 1);
2121 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2124 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2125 QCOMPARE(o.error(), false);
2126 QCOMPARE(o.invoked(), 12);
2127 QCOMPARE(o.actuals().count(), 1);
2128 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2131 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2132 QCOMPARE(o.error(), false);
2133 QCOMPARE(o.invoked(), 12);
2134 QCOMPARE(o.actuals().count(), 1);
2135 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2138 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2139 QCOMPARE(o.error(), false);
2140 QCOMPARE(o.invoked(), 12);
2141 QCOMPARE(o.actuals().count(), 1);
2142 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2145 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2146 QCOMPARE(o.error(), false);
2147 QCOMPARE(o.invoked(), 12);
2148 QCOMPARE(o.actuals().count(), 1);
2149 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2152 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2153 QCOMPARE(o.error(), false);
2154 QCOMPARE(o.invoked(), 12);
2155 QCOMPARE(o.actuals().count(), 1);
2156 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2159 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2160 QCOMPARE(o.error(), false);
2161 QCOMPARE(o.invoked(), 13);
2162 QCOMPARE(o.actuals().count(), 1);
2163 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2166 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2167 QCOMPARE(o.error(), false);
2168 QCOMPARE(o.invoked(), 13);
2169 QCOMPARE(o.actuals().count(), 1);
2170 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2173 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2174 QCOMPARE(o.error(), false);
2175 QCOMPARE(o.invoked(), 13);
2176 QCOMPARE(o.actuals().count(), 1);
2177 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2180 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2181 QCOMPARE(o.error(), false);
2182 QCOMPARE(o.invoked(), 13);
2183 QCOMPARE(o.actuals().count(), 1);
2184 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2187 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2188 QCOMPARE(o.error(), false);
2189 QCOMPARE(o.invoked(), 13);
2190 QCOMPARE(o.actuals().count(), 1);
2191 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2194 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2195 QCOMPARE(o.error(), false);
2196 QCOMPARE(o.invoked(), 14);
2197 QCOMPARE(o.actuals().count(), 1);
2198 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2201 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2202 QCOMPARE(o.error(), false);
2203 QCOMPARE(o.invoked(), 14);
2204 QCOMPARE(o.actuals().count(), 1);
2205 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2208 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2209 QCOMPARE(o.error(), false);
2210 QCOMPARE(o.invoked(), 14);
2211 QCOMPARE(o.actuals().count(), 1);
2212 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2215 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2216 QCOMPARE(o.error(), false);
2217 QCOMPARE(o.invoked(), 14);
2218 QCOMPARE(o.actuals().count(), 1);
2219 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2222 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2223 QCOMPARE(o.error(), false);
2224 QCOMPARE(o.invoked(), 15);
2225 QCOMPARE(o.actuals().count(), 2);
2226 QCOMPARE(o.actuals().at(0), QVariant(4));
2227 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2230 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2231 QCOMPARE(o.error(), false);
2232 QCOMPARE(o.invoked(), 15);
2233 QCOMPARE(o.actuals().count(), 2);
2234 QCOMPARE(o.actuals().at(0), QVariant(8));
2235 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2238 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2239 QCOMPARE(o.error(), false);
2240 QCOMPARE(o.invoked(), 15);
2241 QCOMPARE(o.actuals().count(), 2);
2242 QCOMPARE(o.actuals().at(0), QVariant(3));
2243 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2246 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2247 QCOMPARE(o.error(), false);
2248 QCOMPARE(o.invoked(), 15);
2249 QCOMPARE(o.actuals().count(), 2);
2250 QCOMPARE(o.actuals().at(0), QVariant(44));
2251 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2254 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2255 QCOMPARE(o.error(), false);
2256 QCOMPARE(o.invoked(), -1);
2257 QCOMPARE(o.actuals().count(), 0);
2260 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2261 QCOMPARE(o.error(), false);
2262 QCOMPARE(o.invoked(), 16);
2263 QCOMPARE(o.actuals().count(), 1);
2264 QCOMPARE(o.actuals().at(0), QVariant(10));
2267 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2268 QCOMPARE(o.error(), false);
2269 QCOMPARE(o.invoked(), 17);
2270 QCOMPARE(o.actuals().count(), 2);
2271 QCOMPARE(o.actuals().at(0), QVariant(10));
2272 QCOMPARE(o.actuals().at(1), QVariant(11));
2275 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2276 QCOMPARE(o.error(), false);
2277 QCOMPARE(o.invoked(), 18);
2278 QCOMPARE(o.actuals().count(), 1);
2279 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2282 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2283 QCOMPARE(o.error(), false);
2284 QCOMPARE(o.invoked(), 19);
2285 QCOMPARE(o.actuals().count(), 1);
2286 QCOMPARE(o.actuals().at(0), QVariant(9));
2289 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2290 QCOMPARE(o.error(), false);
2291 QCOMPARE(o.invoked(), 20);
2292 QCOMPARE(o.actuals().count(), 2);
2293 QCOMPARE(o.actuals().at(0), QVariant(10));
2294 QCOMPARE(o.actuals().at(1), QVariant(19));
2297 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2298 QCOMPARE(o.error(), false);
2299 QCOMPARE(o.invoked(), 20);
2300 QCOMPARE(o.actuals().count(), 2);
2301 QCOMPARE(o.actuals().at(0), QVariant(10));
2302 QCOMPARE(o.actuals().at(1), QVariant(13));
2305 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2306 QCOMPARE(o.error(), false);
2307 QCOMPARE(o.invoked(), -3);
2308 QCOMPARE(o.actuals().count(), 1);
2309 QCOMPARE(o.actuals().at(0), QVariant(9));
2312 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2313 QCOMPARE(o.error(), false);
2314 QCOMPARE(o.invoked(), 21);
2315 QCOMPARE(o.actuals().count(), 2);
2316 QCOMPARE(o.actuals().at(0), QVariant(9));
2317 QCOMPARE(o.actuals().at(1), QVariant());
2320 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2321 QCOMPARE(o.error(), false);
2322 QCOMPARE(o.invoked(), 21);
2323 QCOMPARE(o.actuals().count(), 2);
2324 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2325 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2328 // QTBUG-13047 (check that you can pass registered object types as args)
2329 void tst_qdeclarativeecmascript::invokableObjectArg()
2331 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
2333 QObject *o = component.create();
2335 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2337 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2342 // QTBUG-13047 (check that you can return registered object types from methods)
2343 void tst_qdeclarativeecmascript::invokableObjectRet()
2345 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
2347 QObject *o = component.create();
2349 QCOMPARE(o->property("test").toBool(), true);
2354 void tst_qdeclarativeecmascript::listToVariant()
2356 QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
2358 MyQmlContainer container;
2360 QDeclarativeContext context(engine.rootContext());
2361 context.setContextObject(&container);
2363 QObject *object = component.create(&context);
2364 QVERIFY(object != 0);
2366 QVariant v = object->property("test");
2367 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2368 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2374 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2375 void tst_qdeclarativeecmascript::listAssignment()
2377 QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
2378 QObject *obj = component.create();
2379 QCOMPARE(obj->property("list1length").toInt(), 2);
2380 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2381 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2382 QCOMPARE(list1.count(&list1), list2.count(&list2));
2383 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2384 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2389 void tst_qdeclarativeecmascript::multiEngineObject()
2392 obj.setStringProperty("Howdy planet");
2394 QDeclarativeEngine e1;
2395 e1.rootContext()->setContextProperty("thing", &obj);
2396 QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
2398 QDeclarativeEngine e2;
2399 e2.rootContext()->setContextProperty("thing", &obj);
2400 QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
2402 QObject *o1 = c1.create();
2403 QObject *o2 = c2.create();
2405 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2406 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2412 // Test that references to QObjects are cleanup when the object is destroyed
2413 void tst_qdeclarativeecmascript::deletedObject()
2415 QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
2417 QObject *object = component.create();
2419 QCOMPARE(object->property("test1").toBool(), true);
2420 QCOMPARE(object->property("test2").toBool(), true);
2421 QCOMPARE(object->property("test3").toBool(), true);
2422 QCOMPARE(object->property("test4").toBool(), true);
2427 void tst_qdeclarativeecmascript::attachedPropertyScope()
2429 QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
2431 QObject *object = component.create();
2432 QVERIFY(object != 0);
2434 MyQmlAttachedObject *attached =
2435 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2436 QVERIFY(attached != 0);
2438 QCOMPARE(object->property("value2").toInt(), 0);
2440 attached->emitMySignal();
2442 QCOMPARE(object->property("value2").toInt(), 9);
2447 void tst_qdeclarativeecmascript::scriptConnect()
2450 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
2452 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2453 QVERIFY(object != 0);
2455 QCOMPARE(object->property("test").toBool(), false);
2456 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2457 QCOMPARE(object->property("test").toBool(), true);
2463 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.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.3.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.4.qml"));
2491 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2492 QVERIFY(object != 0);
2494 QCOMPARE(object->methodCalled(), false);
2495 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2496 QCOMPARE(object->methodCalled(), true);
2502 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.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.6.qml"));
2517 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2518 QVERIFY(object != 0);
2520 QCOMPARE(object->property("test").toInt(), 0);
2521 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2522 QCOMPARE(object->property("test").toInt(), 2);
2528 void tst_qdeclarativeecmascript::scriptDisconnect()
2531 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
2533 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2534 QVERIFY(object != 0);
2536 QCOMPARE(object->property("test").toInt(), 0);
2537 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2538 QCOMPARE(object->property("test").toInt(), 1);
2539 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2540 QCOMPARE(object->property("test").toInt(), 2);
2541 emit object->basicSignal();
2542 QCOMPARE(object->property("test").toInt(), 2);
2543 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2544 QCOMPARE(object->property("test").toInt(), 2);
2550 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
2552 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2553 QVERIFY(object != 0);
2555 QCOMPARE(object->property("test").toInt(), 0);
2556 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2557 QCOMPARE(object->property("test").toInt(), 1);
2558 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2559 QCOMPARE(object->property("test").toInt(), 2);
2560 emit object->basicSignal();
2561 QCOMPARE(object->property("test").toInt(), 2);
2562 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2563 QCOMPARE(object->property("test").toInt(), 2);
2569 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
2571 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2572 QVERIFY(object != 0);
2574 QCOMPARE(object->property("test").toInt(), 0);
2575 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2576 QCOMPARE(object->property("test").toInt(), 1);
2577 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2578 QCOMPARE(object->property("test").toInt(), 2);
2579 emit object->basicSignal();
2580 QCOMPARE(object->property("test").toInt(), 2);
2581 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2582 QCOMPARE(object->property("test").toInt(), 3);
2587 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
2589 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2590 QVERIFY(object != 0);
2592 QCOMPARE(object->property("test").toInt(), 0);
2593 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2594 QCOMPARE(object->property("test").toInt(), 1);
2595 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2596 QCOMPARE(object->property("test").toInt(), 2);
2597 emit object->basicSignal();
2598 QCOMPARE(object->property("test").toInt(), 2);
2599 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2600 QCOMPARE(object->property("test").toInt(), 3);
2606 class OwnershipObject : public QObject
2610 OwnershipObject() { object = new QObject; }
2612 QPointer<QObject> object;
2615 QObject *getObject() { return object; }
2618 void tst_qdeclarativeecmascript::ownership()
2620 OwnershipObject own;
2621 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2622 context->setContextObject(&own);
2625 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2627 QVERIFY(own.object != 0);
2629 QObject *object = component.create(context);
2631 engine.collectGarbage();
2633 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2634 QCoreApplication::processEvents();
2636 QVERIFY(own.object == 0);
2641 own.object = new QObject(&own);
2644 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2646 QVERIFY(own.object != 0);
2648 QObject *object = component.create(context);
2650 engine.collectGarbage();
2652 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2653 QCoreApplication::processEvents();
2655 QVERIFY(own.object != 0);
2663 class CppOwnershipReturnValue : public QObject
2667 CppOwnershipReturnValue() : value(0) {}
2668 ~CppOwnershipReturnValue() { delete value; }
2670 Q_INVOKABLE QObject *create() {
2671 value = new QObject;
2672 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2676 Q_INVOKABLE MyQmlObject *createQmlObject() {
2677 MyQmlObject *rv = new MyQmlObject;
2682 QPointer<QObject> value;
2686 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2687 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2689 CppOwnershipReturnValue source;
2692 QDeclarativeEngine engine;
2693 engine.rootContext()->setContextProperty("source", &source);
2695 QVERIFY(source.value == 0);
2697 QDeclarativeComponent component(&engine);
2698 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2700 QObject *object = component.create();
2702 QVERIFY(object != 0);
2703 QVERIFY(source.value != 0);
2708 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2709 QCoreApplication::processEvents();
2711 QVERIFY(source.value != 0);
2715 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2717 CppOwnershipReturnValue source;
2720 QDeclarativeEngine engine;
2721 engine.rootContext()->setContextProperty("source", &source);
2723 QVERIFY(source.value == 0);
2725 QDeclarativeComponent component(&engine);
2726 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2728 QObject *object = component.create();
2730 QVERIFY(object != 0);
2731 QVERIFY(source.value != 0);
2736 engine.collectGarbage();
2737 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2738 QCoreApplication::processEvents();
2740 QVERIFY(source.value == 0);
2743 class QListQObjectMethodsObject : public QObject
2747 QListQObjectMethodsObject() {
2748 m_objects.append(new MyQmlObject());
2749 m_objects.append(new MyQmlObject());
2752 ~QListQObjectMethodsObject() {
2753 qDeleteAll(m_objects);
2757 QList<QObject *> getObjects() { return m_objects; }
2760 QList<QObject *> m_objects;
2763 // Tests that returning a QList<QObject*> from a method works
2764 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2766 QListQObjectMethodsObject obj;
2767 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2768 context->setContextObject(&obj);
2770 QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
2772 QObject *object = component.create(context);
2774 QCOMPARE(object->property("test").toInt(), 2);
2775 QCOMPARE(object->property("test2").toBool(), true);
2782 void tst_qdeclarativeecmascript::strictlyEquals()
2784 QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
2786 QObject *object = component.create();
2787 QVERIFY(object != 0);
2789 QCOMPARE(object->property("test1").toBool(), true);
2790 QCOMPARE(object->property("test2").toBool(), true);
2791 QCOMPARE(object->property("test3").toBool(), true);
2792 QCOMPARE(object->property("test4").toBool(), true);
2793 QCOMPARE(object->property("test5").toBool(), true);
2794 QCOMPARE(object->property("test6").toBool(), true);
2795 QCOMPARE(object->property("test7").toBool(), true);
2796 QCOMPARE(object->property("test8").toBool(), true);
2801 void tst_qdeclarativeecmascript::compiled()
2803 QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
2805 QObject *object = component.create();
2806 QVERIFY(object != 0);
2808 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2809 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2810 QCOMPARE(object->property("test3").toBool(), true);
2811 QCOMPARE(object->property("test4").toBool(), false);
2812 QCOMPARE(object->property("test5").toBool(), false);
2813 QCOMPARE(object->property("test6").toBool(), true);
2815 QCOMPARE(object->property("test7").toInt(), 185);
2816 QCOMPARE(object->property("test8").toInt(), 167);
2817 QCOMPARE(object->property("test9").toBool(), true);
2818 QCOMPARE(object->property("test10").toBool(), false);
2819 QCOMPARE(object->property("test11").toBool(), false);
2820 QCOMPARE(object->property("test12").toBool(), true);
2822 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2823 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2824 QCOMPARE(object->property("test15").toBool(), false);
2825 QCOMPARE(object->property("test16").toBool(), true);
2827 QCOMPARE(object->property("test17").toInt(), 5);
2828 QCOMPARE(object->property("test18").toReal(), qreal(176));
2829 QCOMPARE(object->property("test19").toInt(), 7);
2830 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2831 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2832 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2833 QCOMPARE(object->property("test23").toBool(), true);
2834 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2835 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2840 // Test that numbers assigned in bindings as strings work consistently
2841 void tst_qdeclarativeecmascript::numberAssignment()
2843 QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
2845 QObject *object = component.create();
2846 QVERIFY(object != 0);
2848 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2849 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2850 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2851 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2852 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2854 QCOMPARE(object->property("test5"), QVariant((int)7));
2855 QCOMPARE(object->property("test6"), QVariant((int)7));
2856 QCOMPARE(object->property("test7"), QVariant((int)6));
2857 QCOMPARE(object->property("test8"), QVariant((int)6));
2859 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2860 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2861 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2862 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2867 void tst_qdeclarativeecmascript::propertySplicing()
2869 QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
2871 QObject *object = component.create();
2872 QVERIFY(object != 0);
2874 QCOMPARE(object->property("test").toBool(), true);
2880 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2882 QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
2884 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2885 QVERIFY(object != 0);
2887 MyQmlObject::MyType type;
2888 type.value = 0x8971123;
2889 emit object->signalWithUnknownType(type);
2891 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2893 QCOMPARE(result.value, type.value);
2899 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2901 QTest::addColumn<QString>("expression");
2902 QTest::addColumn<QString>("compare");
2904 QString compareStrict("(function(a, b) { return a === b; })");
2905 QTest::newRow("true") << "true" << compareStrict;
2906 QTest::newRow("undefined") << "undefined" << compareStrict;
2907 QTest::newRow("null") << "null" << compareStrict;
2908 QTest::newRow("123") << "123" << compareStrict;
2909 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2911 QString comparePropertiesStrict(
2913 " if (typeof b != 'object')"
2915 " var props = Object.getOwnPropertyNames(b);"
2916 " for (var i = 0; i < props.length; ++i) {"
2917 " var p = props[i];"
2918 " return arguments.callee(a[p], b[p]);"
2921 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2922 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2925 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2927 QFETCH(QString, expression);
2928 QFETCH(QString, compare);
2930 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2931 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2932 QVERIFY(object != 0);
2934 QJSValue value = engine.evaluate(expression);
2935 QVERIFY(!engine.hasUncaughtException());
2936 object->setProperty("expression", expression);
2937 object->setProperty("compare", compare);
2938 object->setProperty("pass", false);
2940 emit object->signalWithVariant(QVariant::fromValue(value));
2941 QVERIFY(object->property("pass").toBool());
2944 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2946 signalWithJSValueInVariant_data();
2949 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2951 QFETCH(QString, expression);
2952 QFETCH(QString, compare);
2954 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2955 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2956 QVERIFY(object != 0);
2959 QJSValue value = engine2.evaluate(expression);
2960 QVERIFY(!engine2.hasUncaughtException());
2961 object->setProperty("expression", expression);
2962 object->setProperty("compare", compare);
2963 object->setProperty("pass", false);
2965 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2966 emit object->signalWithVariant(QVariant::fromValue(value));
2967 QVERIFY(!object->property("pass").toBool());
2970 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2972 signalWithJSValueInVariant_data();
2975 void tst_qdeclarativeecmascript::signalWithQJSValue()
2977 QFETCH(QString, expression);
2978 QFETCH(QString, compare);
2980 QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
2981 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2982 QVERIFY(object != 0);
2984 QJSValue value = engine.evaluate(expression);
2985 QVERIFY(!engine.hasUncaughtException());
2986 object->setProperty("expression", expression);
2987 object->setProperty("compare", compare);
2988 object->setProperty("pass", false);
2990 emit object->signalWithQJSValue(value);
2992 QVERIFY(object->property("pass").toBool());
2993 QVERIFY(object->qjsvalue().strictlyEquals(value));
2996 void tst_qdeclarativeecmascript::moduleApi_data()
2998 QTest::addColumn<QUrl>("testfile");
2999 QTest::addColumn<QString>("errorMessage");
3000 QTest::addColumn<QStringList>("warningMessages");
3001 QTest::addColumn<QStringList>("readProperties");
3002 QTest::addColumn<QVariantList>("readExpectedValues");
3003 QTest::addColumn<QStringList>("writeProperties");
3004 QTest::addColumn<QVariantList>("writeValues");
3005 QTest::addColumn<QStringList>("readBackProperties");
3006 QTest::addColumn<QVariantList>("readBackExpectedValues");
3008 QTest::newRow("qobject, register + read + method")
3009 << testFileUrl("moduleapi/qobjectModuleApi.qml")
3012 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
3013 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
3014 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
3020 QTest::newRow("script, register + read")
3021 << testFileUrl("moduleapi/scriptModuleApi.qml")
3024 << (QStringList() << "scriptTest")
3025 << (QVariantList() << 13)
3031 QTest::newRow("qobject, caching + read")
3032 << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
3035 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3036 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3042 QTest::newRow("script, caching + read")
3043 << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
3046 << (QStringList() << "scriptTest")
3047 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3053 QTest::newRow("qobject, writing + readonly constraints")
3054 << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
3056 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3057 << (QStringList() << "readOnlyProperty" << "writableProperty")
3058 << (QVariantList() << 20 << 50)
3059 << (QStringList() << "firstProperty" << "writableProperty")
3060 << (QVariantList() << 30 << 30)
3061 << (QStringList() << "readOnlyProperty" << "writableProperty")
3062 << (QVariantList() << 20 << 30);
3064 QTest::newRow("script, writing + readonly constraints")
3065 << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
3067 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3068 << (QStringList() << "readBack" << "unchanged")
3069 << (QVariantList() << 13 << 42)
3070 << (QStringList() << "firstProperty" << "secondProperty")
3071 << (QVariantList() << 30 << 30)
3072 << (QStringList() << "readBack" << "unchanged")
3073 << (QVariantList() << 30 << 42);
3075 QTest::newRow("qobject module API enum values in JS")
3076 << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
3079 << (QStringList() << "enumValue" << "enumMethod")
3080 << (QVariantList() << 42 << 30)
3086 QTest::newRow("qobject, invalid major version fail")
3087 << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
3088 << QString("QDeclarativeComponent: Component is not ready")
3097 QTest::newRow("qobject, invalid minor version fail")
3098 << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
3099 << QString("QDeclarativeComponent: Component is not ready")
3109 void tst_qdeclarativeecmascript::moduleApi()
3111 QFETCH(QUrl, testfile);
3112 QFETCH(QString, errorMessage);
3113 QFETCH(QStringList, warningMessages);
3114 QFETCH(QStringList, readProperties);
3115 QFETCH(QVariantList, readExpectedValues);
3116 QFETCH(QStringList, writeProperties);
3117 QFETCH(QVariantList, writeValues);
3118 QFETCH(QStringList, readBackProperties);
3119 QFETCH(QVariantList, readBackExpectedValues);
3121 QDeclarativeComponent component(&engine, testfile);
3123 if (!errorMessage.isEmpty())
3124 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3126 if (warningMessages.size())
3127 foreach (const QString &warning, warningMessages)
3128 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3130 QObject *object = component.create();
3131 if (!errorMessage.isEmpty()) {
3132 QVERIFY(object == 0);
3134 QVERIFY(object != 0);
3135 for (int i = 0; i < readProperties.size(); ++i)
3136 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3137 for (int i = 0; i < writeProperties.size(); ++i)
3138 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3139 for (int i = 0; i < readBackProperties.size(); ++i)
3140 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3145 void tst_qdeclarativeecmascript::importScripts_data()
3147 QTest::addColumn<QUrl>("testfile");
3148 QTest::addColumn<QString>("errorMessage");
3149 QTest::addColumn<QStringList>("warningMessages");
3150 QTest::addColumn<QStringList>("propertyNames");
3151 QTest::addColumn<QVariantList>("propertyValues");
3153 QTest::newRow("basic functionality")
3154 << testFileUrl("jsimport/testImport.qml")
3157 << (QStringList() << QLatin1String("importedScriptStringValue")
3158 << QLatin1String("importedScriptFunctionValue")
3159 << QLatin1String("importedModuleAttachedPropertyValue")
3160 << QLatin1String("importedModuleEnumValue"))
3161 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3166 QTest::newRow("import scoping")
3167 << testFileUrl("jsimport/testImportScoping.qml")
3170 << (QStringList() << QLatin1String("componentError"))
3171 << (QVariantList() << QVariant(5));
3173 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3174 << testFileUrl("jsimportfail/failOne.qml")
3176 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3177 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3178 << (QVariantList() << QVariant(QString()));
3180 QTest::newRow("javascript imports in an import should be private to the import scope")
3181 << testFileUrl("jsimportfail/failTwo.qml")
3183 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3184 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3185 << (QVariantList() << QVariant(QString()));
3187 QTest::newRow("module imports in an import should be private to the import scope")
3188 << testFileUrl("jsimportfail/failThree.qml")
3190 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3191 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3192 << (QVariantList() << QVariant(false));
3194 QTest::newRow("typenames in an import should be private to the import scope")
3195 << testFileUrl("jsimportfail/failFour.qml")
3197 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3198 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3199 << (QVariantList() << QVariant(0));
3201 QTest::newRow("import with imports has it's own activation scope")
3202 << testFileUrl("jsimportfail/failFive.qml")
3204 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3205 << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3206 << (QStringList() << QLatin1String("componentError"))
3207 << (QVariantList() << QVariant(0));
3209 QTest::newRow("import pragma library script")
3210 << testFileUrl("jsimport/testImportPragmaLibrary.qml")
3213 << (QStringList() << QLatin1String("testValue"))
3214 << (QVariantList() << QVariant(31));
3216 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3217 << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
3220 << (QStringList() << QLatin1String("testValue"))
3221 << (QVariantList() << QVariant(0));
3223 QTest::newRow("import pragma library script which has an import")
3224 << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
3227 << (QStringList() << QLatin1String("testValue"))
3228 << (QVariantList() << QVariant(55));
3230 QTest::newRow("import pragma library script which has a pragma library import")
3231 << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3234 << (QStringList() << QLatin1String("testValue"))
3235 << (QVariantList() << QVariant(18));
3238 void tst_qdeclarativeecmascript::importScripts()
3240 QFETCH(QUrl, testfile);
3241 QFETCH(QString, errorMessage);
3242 QFETCH(QStringList, warningMessages);
3243 QFETCH(QStringList, propertyNames);
3244 QFETCH(QVariantList, propertyValues);
3246 QDeclarativeComponent component(&engine, testfile);
3248 if (!errorMessage.isEmpty())
3249 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3251 if (warningMessages.size())
3252 foreach (const QString &warning, warningMessages)
3253 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3255 QObject *object = component.create();
3256 if (!errorMessage.isEmpty()) {
3257 QVERIFY(object == 0);
3259 QVERIFY(object != 0);
3260 for (int i = 0; i < propertyNames.size(); ++i)
3261 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3266 void tst_qdeclarativeecmascript::scarceResources_other()
3268 /* These tests require knowledge of state, since we test values after
3269 performing signal or function invocation. */
3271 QPixmap origPixmap(100, 100);
3272 origPixmap.fill(Qt::blue);
3273 QString srp_name, expectedWarning;
3274 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3275 ScarceResourceObject *eo = 0;
3277 QObject *object = 0;
3279 /* property var semantics */
3281 // test that scarce resources are handled properly in signal invocation
3282 QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
3283 object = varComponentTen.create();
3284 srsc = object->findChild<QObject*>("srsc");
3286 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3287 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3288 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3289 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3290 QMetaObject::invokeMethod(srsc, "testSignal");
3291 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3292 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3293 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3294 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3295 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3296 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3297 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3298 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3299 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3300 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3303 // test that scarce resources are handled properly from js functions in qml files
3304 QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
3305 object = varComponentEleven.create();
3306 QVERIFY(object != 0);
3307 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3308 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3309 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3310 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3311 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3312 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3313 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3314 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3315 QMetaObject::invokeMethod(object, "releaseScarceResource");
3316 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3317 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3318 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3319 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3322 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3323 QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
3324 object = varComponentTwelve.create();
3325 QVERIFY(object != 0);
3326 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3327 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3328 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3329 srp_name = object->property("srp_name").toString();
3330 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3331 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3332 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3333 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3334 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3335 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3336 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3339 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3340 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3341 QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
3342 object = varComponentThirteen.create();
3343 QVERIFY(object != 0);
3344 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3345 QMetaObject::invokeMethod(object, "assignVarProperty");
3346 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3347 QMetaObject::invokeMethod(object, "deassignVarProperty");
3348 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3351 /* property variant semantics */
3353 // test that scarce resources are handled properly in signal invocation
3354 QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
3355 object = variantComponentTen.create();
3356 QVERIFY(object != 0);
3357 srsc = object->findChild<QObject*>("srsc");
3359 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3360 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3361 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3362 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3363 QMetaObject::invokeMethod(srsc, "testSignal");
3364 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3365 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3366 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3367 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3368 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3369 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3370 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3371 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3372 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3373 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3376 // test that scarce resources are handled properly from js functions in qml files
3377 QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
3378 object = variantComponentEleven.create();
3379 QVERIFY(object != 0);
3380 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3381 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3382 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3383 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3384 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3385 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3386 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3387 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3388 QMetaObject::invokeMethod(object, "releaseScarceResource");
3389 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3390 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3391 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3392 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3395 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3396 QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
3397 object = variantComponentTwelve.create();
3398 QVERIFY(object != 0);
3399 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3400 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3401 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3402 srp_name = object->property("srp_name").toString();
3403 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3404 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3405 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3406 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3407 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3408 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3409 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3413 void tst_qdeclarativeecmascript::scarceResources_data()
3415 QTest::addColumn<QUrl>("qmlFile");
3416 QTest::addColumn<bool>("readDetachStatus");
3417 QTest::addColumn<bool>("expectedDetachStatus");
3418 QTest::addColumn<QStringList>("propertyNames");
3419 QTest::addColumn<QVariantList>("expectedValidity");
3420 QTest::addColumn<QVariantList>("expectedValues");
3421 QTest::addColumn<QStringList>("expectedErrors");
3423 QPixmap origPixmap(100, 100);
3424 origPixmap.fill(Qt::blue);
3426 /* property var semantics */
3428 // in the following three cases, the instance created from the component
3429 // has a property which is a copy of the scarce resource; hence, the
3430 // resource should NOT be detached prior to deletion of the object instance,
3431 // unless the resource is destroyed explicitly.
3432 QTest::newRow("var: import scarce resource copy directly")
3433 << testFileUrl("scarceResourceCopy.var.qml")
3435 << false // won't be detached, because assigned to property and not explicitly released
3436 << (QStringList() << QLatin1String("scarceResourceCopy"))
3437 << (QList<QVariant>() << true)
3438 << (QList<QVariant>() << origPixmap)
3441 QTest::newRow("var: import scarce resource copy from JS")
3442 << testFileUrl("scarceResourceCopyFromJs.var.qml")
3444 << false // won't be detached, because assigned to property and not explicitly released
3445 << (QStringList() << QLatin1String("scarceResourceCopy"))
3446 << (QList<QVariant>() << true)
3447 << (QList<QVariant>() << origPixmap)
3450 QTest::newRow("var: import released scarce resource copy from JS")
3451 << testFileUrl("scarceResourceDestroyedCopy.var.qml")
3453 << true // explicitly released, so it will be detached
3454 << (QStringList() << QLatin1String("scarceResourceCopy"))
3455 << (QList<QVariant>() << false)
3456 << (QList<QVariant>() << QVariant())
3459 // in the following three cases, no other copy should exist in memory,
3460 // and so it should be detached (unless explicitly preserved).
3461 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3462 << testFileUrl("scarceResourceTest.var.qml")
3464 << true // auto released, so it will be detached
3465 << (QStringList() << QLatin1String("scarceResourceTest"))
3466 << (QList<QVariant>() << true)
3467 << (QList<QVariant>() << QVariant(100))
3469 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3470 << testFileUrl("scarceResourceTestPreserve.var.qml")
3472 << false // won't be detached because we explicitly preserve it
3473 << (QStringList() << QLatin1String("scarceResourceTest"))
3474 << (QList<QVariant>() << true)
3475 << (QList<QVariant>() << QVariant(100))
3477 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3478 << testFileUrl("scarceResourceTestMultiple.var.qml")
3480 << true // will be detached because all resources were released manually or automatically.
3481 << (QStringList() << QLatin1String("scarceResourceTest"))
3482 << (QList<QVariant>() << true)
3483 << (QList<QVariant>() << QVariant(100))
3486 // In the following three cases, test that scarce resources are handled
3487 // correctly for imports.
3488 QTest::newRow("var: import with no binding")
3489 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3490 << false // cannot check detach status.
3493 << QList<QVariant>()
3494 << QList<QVariant>()
3496 QTest::newRow("var: import with binding without explicit preserve")
3497 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3500 << (QStringList() << QLatin1String("scarceResourceCopy"))
3501 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3502 << (QList<QVariant>() << QVariant())
3504 QTest::newRow("var: import with explicit release after binding evaluation")
3505 << testFileUrl("scarceResourceCopyImport.var.qml")
3508 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3509 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3510 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3512 QTest::newRow("var: import with different js objects")
3513 << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
3516 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3517 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3518 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3520 QTest::newRow("var: import with different js objects and explicit release")
3521 << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
3524 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3525 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3526 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3528 QTest::newRow("var: import with same js objects and explicit release")
3529 << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
3532 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3533 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3534 << (QList<QVariant>() << QVariant() << QVariant())
3536 QTest::newRow("var: binding with same js objects and explicit release")
3537 << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
3540 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3541 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3542 << (QList<QVariant>() << QVariant() << QVariant())
3546 /* property variant semantics */
3548 // in the following three cases, the instance created from the component
3549 // has a property which is a copy of the scarce resource; hence, the
3550 // resource should NOT be detached prior to deletion of the object instance,
3551 // unless the resource is destroyed explicitly.
3552 QTest::newRow("variant: import scarce resource copy directly")
3553 << testFileUrl("scarceResourceCopy.variant.qml")
3555 << false // won't be detached, because assigned to property and not explicitly released
3556 << (QStringList() << QLatin1String("scarceResourceCopy"))
3557 << (QList<QVariant>() << true)
3558 << (QList<QVariant>() << origPixmap)
3561 QTest::newRow("variant: import scarce resource copy from JS")
3562 << testFileUrl("scarceResourceCopyFromJs.variant.qml")
3564 << false // won't be detached, because assigned to property and not explicitly released
3565 << (QStringList() << QLatin1String("scarceResourceCopy"))
3566 << (QList<QVariant>() << true)
3567 << (QList<QVariant>() << origPixmap)
3570 QTest::newRow("variant: import released scarce resource copy from JS")
3571 << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
3573 << true // explicitly released, so it will be detached
3574 << (QStringList() << QLatin1String("scarceResourceCopy"))
3575 << (QList<QVariant>() << false)
3576 << (QList<QVariant>() << QVariant())
3579 // in the following three cases, no other copy should exist in memory,
3580 // and so it should be detached (unless explicitly preserved).
3581 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3582 << testFileUrl("scarceResourceTest.variant.qml")
3584 << true // auto released, so it will be detached
3585 << (QStringList() << QLatin1String("scarceResourceTest"))
3586 << (QList<QVariant>() << true)
3587 << (QList<QVariant>() << QVariant(100))
3589 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3590 << testFileUrl("scarceResourceTestPreserve.variant.qml")
3592 << false // won't be detached because we explicitly preserve it
3593 << (QStringList() << QLatin1String("scarceResourceTest"))
3594 << (QList<QVariant>() << true)
3595 << (QList<QVariant>() << QVariant(100))
3597 QTest::newRow("variant: import multiple scarce resources")
3598 << testFileUrl("scarceResourceTestMultiple.variant.qml")
3600 << true // will be detached because all resources were released manually or automatically.
3601 << (QStringList() << QLatin1String("scarceResourceTest"))
3602 << (QList<QVariant>() << true)
3603 << (QList<QVariant>() << QVariant(100))
3606 // In the following three cases, test that scarce resources are handled
3607 // correctly for imports.
3608 QTest::newRow("variant: import with no binding")
3609 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3610 << false // cannot check detach status.
3613 << QList<QVariant>()
3614 << QList<QVariant>()
3616 QTest::newRow("variant: import with binding without explicit preserve")
3617 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3620 << (QStringList() << QLatin1String("scarceResourceCopy"))
3621 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3622 << (QList<QVariant>() << QVariant())
3624 QTest::newRow("variant: import with explicit release after binding evaluation")
3625 << testFileUrl("scarceResourceCopyImport.variant.qml")
3628 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3629 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3630 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3634 void tst_qdeclarativeecmascript::scarceResources()
3636 QFETCH(QUrl, qmlFile);
3637 QFETCH(bool, readDetachStatus);
3638 QFETCH(bool, expectedDetachStatus);
3639 QFETCH(QStringList, propertyNames);
3640 QFETCH(QVariantList, expectedValidity);
3641 QFETCH(QVariantList, expectedValues);
3642 QFETCH(QStringList, expectedErrors);
3644 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3645 ScarceResourceObject *eo = 0;
3646 QObject *object = 0;
3648 QDeclarativeComponent c(&engine, qmlFile);
3649 object = c.create();
3650 QVERIFY(object != 0);
3651 for (int i = 0; i < propertyNames.size(); ++i) {
3652 QString prop = propertyNames.at(i);
3653 bool validity = expectedValidity.at(i).toBool();
3654 QVariant value = expectedValues.at(i);
3656 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3657 if (value.type() == QVariant::Int) {
3658 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3659 } else if (value.type() == QVariant::Pixmap) {
3660 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3664 if (readDetachStatus) {
3665 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3666 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3669 QVERIFY(ep->scarceResources.isEmpty());
3673 void tst_qdeclarativeecmascript::propertyChangeSlots()
3675 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3676 QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
3677 QObject *object = component.create();
3678 QVERIFY(object != 0);
3681 // ensure that invalid property names fail properly.
3682 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3683 QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
3684 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3685 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3686 object = e1.create();
3687 QVERIFY(object == 0);
3690 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3691 QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
3692 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3693 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3694 object = e2.create();
3695 QVERIFY(object == 0);
3698 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3699 QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
3700 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3701 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3702 object = e3.create();
3703 QVERIFY(object == 0);
3706 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3707 QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
3708 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3709 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3710 object = e4.create();
3711 QVERIFY(object == 0);
3715 void tst_qdeclarativeecmascript::propertyVar_data()
3717 QTest::addColumn<QUrl>("qmlFile");
3720 QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
3721 QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
3722 QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
3723 QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
3724 QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
3725 QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
3726 QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
3727 QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
3728 QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
3729 QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
3732 void tst_qdeclarativeecmascript::propertyVar()
3734 QFETCH(QUrl, qmlFile);
3736 QDeclarativeComponent component(&engine, qmlFile);
3737 QObject *object = component.create();
3738 QVERIFY(object != 0);
3740 QCOMPARE(object->property("test").toBool(), true);
3745 // Tests that we can write QVariant values to var properties from C++
3746 void tst_qdeclarativeecmascript::propertyVarCpp()
3748 QObject *object = 0;
3750 // ensure that writing to and reading from a var property from cpp works as required.
3751 // Literal values stored in var properties can be read and written as QVariants
3752 // of a specific type, whereas object values are read as QVariantMaps.
3753 QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
3754 object = component.create();
3755 QVERIFY(object != 0);
3756 // assign int to property var that currently has int assigned
3757 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3758 QCOMPARE(object->property("varBound"), QVariant(15));
3759 QCOMPARE(object->property("intBound"), QVariant(15));
3760 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3761 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3762 // assign string to property var that current has bool assigned
3763 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3764 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3765 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3766 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3767 // now enforce behaviour when accessing JavaScript objects from cpp.
3768 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3772 static void gc(QDeclarativeEngine &engine)
3774 engine.collectGarbage();
3775 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
3776 QCoreApplication::processEvents();
3779 void tst_qdeclarativeecmascript::propertyVarOwnership()
3781 // Referenced JS objects are not collected
3783 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
3784 QObject *object = component.create();
3785 QVERIFY(object != 0);
3786 QCOMPARE(object->property("test").toBool(), false);
3787 QMetaObject::invokeMethod(object, "runTest");
3788 QCOMPARE(object->property("test").toBool(), true);
3791 // Referenced JS objects are not collected
3793 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
3794 QObject *object = component.create();
3795 QVERIFY(object != 0);
3796 QCOMPARE(object->property("test").toBool(), false);
3797 QMetaObject::invokeMethod(object, "runTest");
3798 QCOMPARE(object->property("test").toBool(), true);
3801 // Qt objects are not collected until they've been dereferenced
3803 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
3804 QObject *object = component.create();
3805 QVERIFY(object != 0);
3807 QCOMPARE(object->property("test2").toBool(), false);
3808 QCOMPARE(object->property("test2").toBool(), false);
3810 QMetaObject::invokeMethod(object, "runTest");
3811 QCOMPARE(object->property("test1").toBool(), true);
3813 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3814 QVERIFY(!referencedObject.isNull());
3816 QVERIFY(!referencedObject.isNull());
3818 QMetaObject::invokeMethod(object, "runTest2");
3819 QCOMPARE(object->property("test2").toBool(), true);
3821 QVERIFY(referencedObject.isNull());
3825 // Self reference does not prevent Qt object collection
3827 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
3828 QObject *object = component.create();
3829 QVERIFY(object != 0);
3831 QCOMPARE(object->property("test").toBool(), true);
3833 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3834 QVERIFY(!referencedObject.isNull());
3836 QVERIFY(!referencedObject.isNull());
3838 QMetaObject::invokeMethod(object, "runTest");
3840 QVERIFY(referencedObject.isNull());
3846 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3848 // The childObject has a reference to a different QObject. We want to ensure
3849 // that the different item will not be cleaned up until required. IE, the childObject
3850 // has implicit ownership of the constructed QObject.
3851 QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
3852 QObject *object = component.create();
3853 QVERIFY(object != 0);
3854 QMetaObject::invokeMethod(object, "assignCircular");
3855 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3856 QCoreApplication::processEvents();
3857 QObject *rootObject = object->property("vp").value<QObject*>();
3858 QVERIFY(rootObject != 0);
3859 QObject *childObject = rootObject->findChild<QObject*>("text");
3860 QVERIFY(childObject != 0);
3861 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3862 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3863 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3864 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3865 QVERIFY(!qobjectGuard.isNull());
3866 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3867 QCoreApplication::processEvents();
3868 QVERIFY(!qobjectGuard.isNull());
3869 QMetaObject::invokeMethod(object, "deassignCircular");
3870 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3871 QCoreApplication::processEvents();
3872 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3876 void tst_qdeclarativeecmascript::propertyVarReparent()
3878 // ensure that nothing breaks if we re-parent objects
3879 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3880 QObject *object = component.create();
3881 QVERIFY(object != 0);
3882 QMetaObject::invokeMethod(object, "assignVarProp");
3883 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3884 QCoreApplication::processEvents();
3885 QObject *rect = object->property("vp").value<QObject*>();
3886 QObject *text = rect->findChild<QObject*>("textOne");
3887 QObject *text2 = rect->findChild<QObject*>("textTwo");
3888 QWeakPointer<QObject> rectGuard(rect);
3889 QWeakPointer<QObject> textGuard(text);
3890 QWeakPointer<QObject> text2Guard(text2);
3891 QVERIFY(!rectGuard.isNull());
3892 QVERIFY(!textGuard.isNull());
3893 QVERIFY(!text2Guard.isNull());
3894 QCOMPARE(text->property("textCanary").toInt(), 11);
3895 QCOMPARE(text2->property("textCanary").toInt(), 12);
3896 // now construct an image which we will reparent.
3897 QMetaObject::invokeMethod(text2, "constructQObject");
3898 QObject *image = text2->property("vp").value<QObject*>();
3899 QWeakPointer<QObject> imageGuard(image);
3900 QVERIFY(!imageGuard.isNull());
3901 QCOMPARE(image->property("imageCanary").toInt(), 13);
3902 // now reparent the "Image" object (currently, it has JS ownership)
3903 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3904 QMetaObject::invokeMethod(text2, "deassignVp");
3905 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3906 QCoreApplication::processEvents();
3907 QCOMPARE(text->property("textCanary").toInt(), 11);
3908 QCOMPARE(text2->property("textCanary").toInt(), 22);
3909 QVERIFY(!imageGuard.isNull()); // should still be alive.
3910 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3911 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3912 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3913 QCoreApplication::processEvents();
3914 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3918 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3920 // sometimes reparenting can cause problems
3921 // (eg, if the ctxt is collected, varproperties are no longer available)
3922 // this test ensures that no crash occurs in that situation.
3923 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3924 QObject *object = component.create();
3925 QVERIFY(object != 0);
3926 QMetaObject::invokeMethod(object, "assignVarProp");
3927 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3928 QCoreApplication::processEvents();
3929 QObject *rect = object->property("vp").value<QObject*>();
3930 QObject *text = rect->findChild<QObject*>("textOne");
3931 QObject *text2 = rect->findChild<QObject*>("textTwo");
3932 QWeakPointer<QObject> rectGuard(rect);
3933 QWeakPointer<QObject> textGuard(text);
3934 QWeakPointer<QObject> text2Guard(text2);
3935 QVERIFY(!rectGuard.isNull());
3936 QVERIFY(!textGuard.isNull());
3937 QVERIFY(!text2Guard.isNull());
3938 QCOMPARE(text->property("textCanary").toInt(), 11);
3939 QCOMPARE(text2->property("textCanary").toInt(), 12);
3940 // now construct an image which we will reparent.
3941 QMetaObject::invokeMethod(text2, "constructQObject");
3942 QObject *image = text2->property("vp").value<QObject*>();
3943 QWeakPointer<QObject> imageGuard(image);
3944 QVERIFY(!imageGuard.isNull());
3945 QCOMPARE(image->property("imageCanary").toInt(), 13);
3946 // now reparent the "Image" object (currently, it has JS ownership)
3947 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3948 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3949 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3950 QCoreApplication::processEvents();
3951 QVERIFY(!imageGuard.isNull()); // should still be alive.
3952 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3954 QVERIFY(imageGuard.isNull()); // should now be dead.
3957 void tst_qdeclarativeecmascript::propertyVarCircular()
3959 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3960 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
3961 QObject *object = component.create();
3962 QVERIFY(object != 0);
3963 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3964 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3965 QCoreApplication::processEvents();
3966 QCOMPARE(object->property("canaryInt"), QVariant(5));
3967 QVariant canaryResourceVariant = object->property("canaryResource");
3968 QVERIFY(canaryResourceVariant.isValid());
3969 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3970 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3971 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3972 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3973 QCoreApplication::processEvents();
3974 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3975 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3976 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3977 QCoreApplication::processEvents();
3978 QCOMPARE(object->property("canaryInt"), QVariant(2));
3979 QCOMPARE(object->property("canaryResource"), QVariant(1));
3980 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3984 void tst_qdeclarativeecmascript::propertyVarCircular2()
3986 // track deletion of JS-owned parent item with Cpp-owned child
3987 // where the child has a var property referencing its parent.
3988 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
3989 QObject *object = component.create();
3990 QVERIFY(object != 0);
3991 QMetaObject::invokeMethod(object, "assignCircular");
3992 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3993 QCoreApplication::processEvents();
3994 QObject *rootObject = object->property("vp").value<QObject*>();
3995 QVERIFY(rootObject != 0);
3996 QObject *childObject = rootObject->findChild<QObject*>("text");
3997 QVERIFY(childObject != 0);
3998 QWeakPointer<QObject> rootObjectTracker(rootObject);
3999 QVERIFY(!rootObjectTracker.isNull());
4000 QWeakPointer<QObject> childObjectTracker(childObject);
4001 QVERIFY(!childObjectTracker.isNull());
4003 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4004 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4005 QMetaObject::invokeMethod(object, "deassignCircular");
4006 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4007 QCoreApplication::processEvents();
4008 QVERIFY(rootObjectTracker.isNull()); // should have been collected
4009 QVERIFY(childObjectTracker.isNull()); // should have been collected
4013 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
4015 *(int*)(parameter) += 1;
4016 qPersistentDispose(object);
4019 void tst_qdeclarativeecmascript::propertyVarInheritance()
4021 int propertyVarWeakRefCallbackCount = 0;
4023 // enforce behaviour regarding element inheritance - ensure handle disposal.
4024 // The particular component under test here has a chain of references.
4025 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
4026 QObject *object = component.create();
4027 QVERIFY(object != 0);
4028 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
4029 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4030 QCoreApplication::processEvents();
4031 // we want to be able to track when the varProperties array of the last metaobject is disposed
4032 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
4033 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*>();
4034 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
4035 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
4036 v8::Persistent<v8::Value> icoCanaryHandle;
4037 v8::Persistent<v8::Value> ccoCanaryHandle;
4040 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4041 // public function which can return us a handle to something in the varProperties array.
4042 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4043 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4044 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4045 // as the varproperties array of each vmemo still references the resource.
4046 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4047 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4049 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4051 // now we deassign the var prop, which should trigger collection of item subtrees.
4052 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4053 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4054 QCoreApplication::processEvents();
4055 // ensure that there are only weak handles to the underlying varProperties array remaining.
4057 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4059 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4060 // to what remains are weak, all varProperties arrays must have been collected.
4063 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4065 int propertyVarWeakRefCallbackCount = 0;
4067 // The particular component under test here does NOT have a chain of references; the
4068 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4069 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4070 QObject *object = component.create();
4071 QVERIFY(object != 0);
4072 QMetaObject::invokeMethod(object, "assignCircular");
4073 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4074 QCoreApplication::processEvents();
4075 QObject *rootObject = object->property("vp").value<QObject*>();
4076 QVERIFY(rootObject != 0);
4077 QObject *childObject = rootObject->findChild<QObject*>("text");
4078 QVERIFY(childObject != 0);
4079 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4080 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4081 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4084 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4085 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
4086 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4088 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4089 QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
4090 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4092 QMetaObject::invokeMethod(object, "deassignCircular");
4093 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4094 QCoreApplication::processEvents();
4095 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4099 // Ensure that QObject type conversion works on binding assignment
4100 void tst_qdeclarativeecmascript::elementAssign()
4102 QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
4104 QObject *object = component.create();
4105 QVERIFY(object != 0);
4107 QCOMPARE(object->property("test").toBool(), true);
4113 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4115 QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
4117 QObject *object = component.create();
4118 QVERIFY(object != 0);
4120 QCOMPARE(object->property("test").toBool(), true);
4126 void tst_qdeclarativeecmascript::objectConversion()
4128 QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
4130 QObject *object = component.create();
4131 QVERIFY(object != 0);
4133 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4134 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4141 void tst_qdeclarativeecmascript::booleanConversion()
4143 QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
4145 QObject *object = component.create();
4146 QVERIFY(object != 0);
4148 QCOMPARE(object->property("test_true1").toBool(), true);
4149 QCOMPARE(object->property("test_true2").toBool(), true);
4150 QCOMPARE(object->property("test_true3").toBool(), true);
4151 QCOMPARE(object->property("test_true4").toBool(), true);
4152 QCOMPARE(object->property("test_true5").toBool(), true);
4154 QCOMPARE(object->property("test_false1").toBool(), false);
4155 QCOMPARE(object->property("test_false2").toBool(), false);
4156 QCOMPARE(object->property("test_false3").toBool(), false);
4161 void tst_qdeclarativeecmascript::handleReferenceManagement()
4166 // Linear QObject reference
4167 QDeclarativeEngine hrmEngine;
4168 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
4169 QObject *object = component.create();
4170 QVERIFY(object != 0);
4171 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4172 cro->setEngine(&hrmEngine);
4173 cro->setDtorCount(&dtorCount);
4174 QMetaObject::invokeMethod(object, "createReference");
4176 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4178 hrmEngine.collectGarbage();
4179 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4180 QCoreApplication::processEvents();
4181 QCOMPARE(dtorCount, 3);
4186 // Circular QObject reference
4187 QDeclarativeEngine hrmEngine;
4188 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
4189 QObject *object = component.create();
4190 QVERIFY(object != 0);
4191 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4192 cro->setEngine(&hrmEngine);
4193 cro->setDtorCount(&dtorCount);
4194 QMetaObject::invokeMethod(object, "circularReference");
4196 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4198 hrmEngine.collectGarbage();
4199 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4200 QCoreApplication::processEvents();
4201 QCOMPARE(dtorCount, 3);
4206 // Linear handle reference
4207 QDeclarativeEngine hrmEngine;
4208 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
4209 QObject *object = component.create();
4210 QVERIFY(object != 0);
4211 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4213 crh->setEngine(&hrmEngine);
4214 crh->setDtorCount(&dtorCount);
4215 QMetaObject::invokeMethod(object, "createReference");
4216 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4217 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4218 QVERIFY(first != 0);
4219 QVERIFY(second != 0);
4220 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4221 // now we have to reparent second and make second owned by JS.
4222 second->setParent(0);
4223 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4225 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4227 hrmEngine.collectGarbage();
4228 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4229 QCoreApplication::processEvents();
4230 QCOMPARE(dtorCount, 3);
4235 // Circular handle reference
4236 QDeclarativeEngine hrmEngine;
4237 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
4238 QObject *object = component.create();
4239 QVERIFY(object != 0);
4240 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4242 crh->setEngine(&hrmEngine);
4243 crh->setDtorCount(&dtorCount);
4244 QMetaObject::invokeMethod(object, "circularReference");
4245 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4246 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4247 QVERIFY(first != 0);
4248 QVERIFY(second != 0);
4249 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4250 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4251 // now we have to reparent and change ownership.
4252 first->setParent(0);
4253 second->setParent(0);
4254 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4255 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4257 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4259 hrmEngine.collectGarbage();
4260 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4261 QCoreApplication::processEvents();
4262 QCOMPARE(dtorCount, 3);
4267 // multiple engine interaction - linear reference
4268 QDeclarativeEngine hrmEngine1;
4269 QDeclarativeEngine hrmEngine2;
4270 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4271 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4272 QObject *object1 = component1.create();
4273 QObject *object2 = component2.create();
4274 QVERIFY(object1 != 0);
4275 QVERIFY(object2 != 0);
4276 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4277 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4280 crh1->setEngine(&hrmEngine1);
4281 crh2->setEngine(&hrmEngine2);
4282 crh1->setDtorCount(&dtorCount);
4283 crh2->setDtorCount(&dtorCount);
4284 QMetaObject::invokeMethod(object1, "createReference");
4285 QMetaObject::invokeMethod(object2, "createReference");
4286 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4287 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4288 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4289 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4290 QVERIFY(first1 != 0);
4291 QVERIFY(second1 != 0);
4292 QVERIFY(first2 != 0);
4293 QVERIFY(second2 != 0);
4294 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4295 // now we have to reparent second2 and make second2 owned by JS.
4296 second2->setParent(0);
4297 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4299 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4300 QCoreApplication::processEvents();
4301 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4304 hrmEngine1.collectGarbage();
4305 hrmEngine2.collectGarbage();
4306 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4307 QCoreApplication::processEvents();
4308 QCOMPARE(dtorCount, 6);
4313 // multiple engine interaction - circular reference
4314 QDeclarativeEngine hrmEngine1;
4315 QDeclarativeEngine hrmEngine2;
4316 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4317 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4318 QObject *object1 = component1.create();
4319 QObject *object2 = component2.create();
4320 QVERIFY(object1 != 0);
4321 QVERIFY(object2 != 0);
4322 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4323 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4326 crh1->setEngine(&hrmEngine1);
4327 crh2->setEngine(&hrmEngine2);
4328 crh1->setDtorCount(&dtorCount);
4329 crh2->setDtorCount(&dtorCount);
4330 QMetaObject::invokeMethod(object1, "createReference");
4331 QMetaObject::invokeMethod(object2, "createReference");
4332 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4333 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4334 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4335 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4336 QVERIFY(first1 != 0);
4337 QVERIFY(second1 != 0);
4338 QVERIFY(first2 != 0);
4339 QVERIFY(second2 != 0);
4340 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4341 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4342 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4343 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4344 // now we have to reparent and change ownership to JS.
4345 first1->setParent(0);
4346 second1->setParent(0);
4347 first2->setParent(0);
4348 second2->setParent(0);
4349 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4350 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4351 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4352 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4354 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4355 QCoreApplication::processEvents();
4356 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4359 hrmEngine1.collectGarbage();
4360 hrmEngine2.collectGarbage();
4361 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4362 QCoreApplication::processEvents();
4363 QCOMPARE(dtorCount, 6);
4368 // multiple engine interaction - linear reference with engine deletion
4369 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4370 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4371 QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4372 QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4373 QObject *object1 = component1.create();
4374 QObject *object2 = component2.create();
4375 QVERIFY(object1 != 0);
4376 QVERIFY(object2 != 0);
4377 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4378 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4381 crh1->setEngine(hrmEngine1);
4382 crh2->setEngine(hrmEngine2);
4383 crh1->setDtorCount(&dtorCount);
4384 crh2->setDtorCount(&dtorCount);
4385 QMetaObject::invokeMethod(object1, "createReference");
4386 QMetaObject::invokeMethod(object2, "createReference");
4387 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4388 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4389 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4390 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4391 QVERIFY(first1 != 0);
4392 QVERIFY(second1 != 0);
4393 QVERIFY(first2 != 0);
4394 QVERIFY(second2 != 0);
4395 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4396 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4397 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4398 // now we have to reparent and change ownership to JS.
4399 first1->setParent(crh1);
4400 second1->setParent(0);
4401 first2->setParent(0);
4402 second2->setParent(0);
4403 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4404 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4405 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4407 QCOMPARE(dtorCount, 0);
4410 QCOMPARE(dtorCount, 0);
4413 hrmEngine1->collectGarbage();
4414 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4415 QCoreApplication::processEvents();
4416 QCOMPARE(dtorCount, 6);
4421 void tst_qdeclarativeecmascript::stringArg()
4423 QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
4424 QObject *object = component.create();
4425 QVERIFY(object != 0);
4426 QMetaObject::invokeMethod(object, "success");
4427 QVERIFY(object->property("returnValue").toBool());
4429 QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4430 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4431 QMetaObject::invokeMethod(object, "failure");
4432 QVERIFY(object->property("returnValue").toBool());
4437 void tst_qdeclarativeecmascript::readonlyDeclaration()
4439 QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
4441 QObject *object = component.create();
4442 QVERIFY(object != 0);
4444 QCOMPARE(object->property("test").toBool(), true);
4449 Q_DECLARE_METATYPE(QList<int>)
4450 Q_DECLARE_METATYPE(QList<qreal>)
4451 Q_DECLARE_METATYPE(QList<bool>)
4452 Q_DECLARE_METATYPE(QList<QString>)
4453 Q_DECLARE_METATYPE(QList<QUrl>)
4454 void tst_qdeclarativeecmascript::sequenceConversionRead()
4457 QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
4458 QDeclarativeComponent component(&engine, qmlFile);
4459 QObject *object = component.create();
4460 QVERIFY(object != 0);
4461 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4464 QMetaObject::invokeMethod(object, "readSequences");
4465 QList<int> intList; intList << 1 << 2 << 3 << 4;
4466 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4467 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4468 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4469 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4470 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4471 QList<bool> boolList; boolList << true << false << true << false;
4472 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4473 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4474 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4475 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4476 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4477 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4478 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4479 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4480 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4481 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4482 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4484 QMetaObject::invokeMethod(object, "readSequenceElements");
4485 QCOMPARE(object->property("intVal").toInt(), 2);
4486 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4487 QCOMPARE(object->property("boolVal").toBool(), false);
4488 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4489 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4490 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4492 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4493 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4495 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4496 QDeclarativeProperty seqProp(seq, "intListProperty");
4497 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4498 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4499 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4501 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4502 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4508 QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
4509 QDeclarativeComponent component(&engine, qmlFile);
4510 QObject *object = component.create();
4511 QVERIFY(object != 0);
4512 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4515 // we haven't registered QList<QPoint> as a sequence type.
4516 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4517 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4518 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4519 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4521 QMetaObject::invokeMethod(object, "performTest");
4523 // QList<QPoint> has not been registered as a sequence type.
4524 QCOMPARE(object->property("pointListLength").toInt(), 0);
4525 QVERIFY(!object->property("pointList").isValid());
4526 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4527 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4528 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4534 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4537 QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
4538 QDeclarativeComponent component(&engine, qmlFile);
4539 QObject *object = component.create();
4540 QVERIFY(object != 0);
4541 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4544 QMetaObject::invokeMethod(object, "writeSequences");
4545 QCOMPARE(object->property("success").toBool(), true);
4547 QMetaObject::invokeMethod(object, "writeSequenceElements");
4548 QCOMPARE(object->property("success").toBool(), true);
4550 QMetaObject::invokeMethod(object, "writeOtherElements");
4551 QCOMPARE(object->property("success").toBool(), true);
4553 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4554 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4560 QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
4561 QDeclarativeComponent component(&engine, qmlFile);
4562 QObject *object = component.create();
4563 QVERIFY(object != 0);
4564 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4567 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4568 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4569 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4571 QMetaObject::invokeMethod(object, "performTest");
4573 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4574 QCOMPARE(seq->pointListProperty(), pointList);
4580 void tst_qdeclarativeecmascript::sequenceConversionArray()
4582 // ensure that in JS the returned sequences act just like normal JS Arrays.
4583 QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
4584 QDeclarativeComponent component(&engine, qmlFile);
4585 QObject *object = component.create();
4586 QVERIFY(object != 0);
4587 QMetaObject::invokeMethod(object, "indexedAccess");
4588 QVERIFY(object->property("success").toBool());
4589 QMetaObject::invokeMethod(object, "arrayOperations");
4590 QVERIFY(object->property("success").toBool());
4591 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4592 QVERIFY(object->property("success").toBool());
4593 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4594 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4598 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4600 // ensure that sequence conversion operations work correctly in a worker thread
4601 // and that serialisation between the main and worker thread succeeds.
4602 QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
4603 QDeclarativeComponent component(&engine, qmlFile);
4604 QObject *object = component.create();
4605 QVERIFY(object != 0);
4607 QMetaObject::invokeMethod(object, "testIntSequence");
4608 QTRY_VERIFY(object->property("finished").toBool());
4609 QVERIFY(object->property("success").toBool());
4611 QMetaObject::invokeMethod(object, "testQrealSequence");
4612 QTRY_VERIFY(object->property("finished").toBool());
4613 QVERIFY(object->property("success").toBool());
4615 QMetaObject::invokeMethod(object, "testBoolSequence");
4616 QTRY_VERIFY(object->property("finished").toBool());
4617 QVERIFY(object->property("success").toBool());
4619 QMetaObject::invokeMethod(object, "testStringSequence");
4620 QTRY_VERIFY(object->property("finished").toBool());
4621 QVERIFY(object->property("success").toBool());
4623 QMetaObject::invokeMethod(object, "testQStringSequence");
4624 QTRY_VERIFY(object->property("finished").toBool());
4625 QVERIFY(object->property("success").toBool());
4627 QMetaObject::invokeMethod(object, "testUrlSequence");
4628 QTRY_VERIFY(object->property("finished").toBool());
4629 QVERIFY(object->property("success").toBool());
4631 QMetaObject::invokeMethod(object, "testVariantSequence");
4632 QTRY_VERIFY(object->property("finished").toBool());
4633 QVERIFY(object->property("success").toBool());
4638 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4641 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
4642 QDeclarativeComponent component(&engine, qmlFile);
4643 QObject *object = component.create();
4644 QVERIFY(object != 0);
4645 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4646 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4647 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4648 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4649 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4654 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
4655 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4656 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4657 QDeclarativeComponent component(&engine, qmlFile);
4658 QObject *object = component.create();
4659 QVERIFY(object != 0);
4664 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4666 QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
4667 QDeclarativeComponent component(&engine, qmlFile);
4668 QObject *object = component.create();
4669 QVERIFY(object != 0);
4670 QMetaObject::invokeMethod(object, "testCopySequences");
4671 QCOMPARE(object->property("success").toBool(), true);
4672 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4673 QCOMPARE(object->property("success").toBool(), true);
4674 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4675 QCOMPARE(object->property("success").toBool(), true);
4679 void tst_qdeclarativeecmascript::assignSequenceTypes()
4681 // test binding array to sequence type property
4683 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
4684 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4685 QVERIFY(object != 0);
4686 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4687 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4688 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4689 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4690 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4691 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4695 // test binding literal to sequence type property
4697 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
4698 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4699 QVERIFY(object != 0);
4700 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4701 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4702 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4703 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4704 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4705 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4709 // test binding single value to sequence type property
4711 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
4712 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4713 QVERIFY(object != 0);
4714 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4715 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4716 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4717 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4721 // test assigning array to sequence type property in js function
4723 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
4724 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4725 QVERIFY(object != 0);
4726 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4727 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4728 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4729 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4730 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4731 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4735 // test assigning literal to sequence type property in js function
4737 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
4738 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4739 QVERIFY(object != 0);
4740 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4741 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4742 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4743 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4744 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4745 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4749 // test assigning single value to sequence type property in js function
4751 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
4752 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4753 QVERIFY(object != 0);
4754 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4755 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4756 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4757 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4761 // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
4763 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
4764 QObject *object = component.create();
4765 QVERIFY(object != 0);
4766 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
4767 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
4768 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
4769 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
4770 MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
4771 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
4772 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4773 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4774 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4775 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4776 QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4781 // Test that assigning a null object works
4782 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4783 void tst_qdeclarativeecmascript::nullObjectBinding()
4785 QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
4787 QObject *object = component.create();
4788 QVERIFY(object != 0);
4790 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4795 // Test that bindings don't evaluate once the engine has been destroyed
4796 void tst_qdeclarativeecmascript::deletedEngine()
4798 QDeclarativeEngine *engine = new QDeclarativeEngine;
4799 QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
4801 QObject *object = component.create();
4802 QVERIFY(object != 0);
4804 QCOMPARE(object->property("a").toInt(), 39);
4805 object->setProperty("b", QVariant(9));
4806 QCOMPARE(object->property("a").toInt(), 117);
4810 QCOMPARE(object->property("a").toInt(), 117);
4811 object->setProperty("b", QVariant(10));
4812 QCOMPARE(object->property("a").toInt(), 117);
4817 // Test the crashing part of QTBUG-9705
4818 void tst_qdeclarativeecmascript::libraryScriptAssert()
4820 QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
4822 QObject *object = component.create();
4823 QVERIFY(object != 0);
4828 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4830 QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
4832 QObject *object = component.create();
4833 QVERIFY(object != 0);
4835 QCOMPARE(object->property("test1").toInt(), 10);
4836 QCOMPARE(object->property("test2").toInt(), 11);
4838 object->setProperty("runTest", true);
4840 QCOMPARE(object->property("test1"), QVariant());
4841 QCOMPARE(object->property("test2"), QVariant());
4847 void tst_qdeclarativeecmascript::qtbug_9792()
4849 QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
4851 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4853 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4854 QVERIFY(object != 0);
4856 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4857 object->basicSignal();
4861 transientErrorsMsgCount = 0;
4862 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4864 object->basicSignal();
4866 qInstallMsgHandler(old);
4868 QCOMPARE(transientErrorsMsgCount, 0);
4873 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4874 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4876 QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
4878 QObject *o = component.create();
4881 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4882 QVERIFY(nested != 0);
4884 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4887 nested = qvariant_cast<QObject *>(o->property("object"));
4888 QVERIFY(nested == 0);
4890 // If the bug is present, the next line will crash
4894 // Test that we shut down without stupid warnings
4895 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4898 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
4900 QObject *o = component.create();
4902 transientErrorsMsgCount = 0;
4903 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4907 qInstallMsgHandler(old);
4909 QCOMPARE(transientErrorsMsgCount, 0);
4914 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
4916 QObject *o = component.create();
4918 transientErrorsMsgCount = 0;
4919 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4923 qInstallMsgHandler(old);
4925 QCOMPARE(transientErrorsMsgCount, 0);
4929 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4932 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
4934 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4937 QVERIFY(o->objectProperty() != 0);
4939 o->setProperty("runTest", true);
4941 QVERIFY(o->objectProperty() == 0);
4947 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
4949 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4952 QVERIFY(o->objectProperty() == 0);
4958 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4960 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
4962 QString url = component.url().toString();
4963 QString warning = url + ":4: Unable to assign a function to a property.";
4964 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4966 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4969 QVERIFY(!o->property("a").isValid());
4974 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4976 QFETCH(QString, triggerProperty);
4978 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4979 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4981 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4983 QVERIFY(!o->property("a").isValid());
4985 o->setProperty("aNumber", QVariant(5));
4986 o->setProperty(triggerProperty.toUtf8().constData(), true);
4987 QCOMPARE(o->property("a"), QVariant(50));
4989 o->setProperty("aNumber", QVariant(10));
4990 QCOMPARE(o->property("a"), QVariant(100));
4995 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4997 QTest::addColumn<QString>("triggerProperty");
4999 QTest::newRow("assign to property") << "assignToProperty";
5000 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
5002 QTest::newRow("assign to value type") << "assignToValueType";
5004 QTest::newRow("use 'this'") << "assignWithThis";
5005 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
5008 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
5010 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
5011 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
5013 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5015 QVERIFY(!o->property("a").isValid());
5017 o->setProperty("assignFuncWithoutReturn", true);
5018 QVERIFY(!o->property("a").isValid());
5020 QString url = component.url().toString();
5021 QString warning = url + ":67: Unable to assign QString to int";
5022 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5023 o->setProperty("assignWrongType", true);
5025 warning = url + ":71: Unable to assign QString to int";
5026 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5027 o->setProperty("assignWrongTypeToValueType", true);
5032 void tst_qdeclarativeecmascript::eval()
5034 QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
5036 QObject *o = component.create();
5039 QCOMPARE(o->property("test1").toBool(), true);
5040 QCOMPARE(o->property("test2").toBool(), true);
5041 QCOMPARE(o->property("test3").toBool(), true);
5042 QCOMPARE(o->property("test4").toBool(), true);
5043 QCOMPARE(o->property("test5").toBool(), true);
5048 void tst_qdeclarativeecmascript::function()
5050 QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
5052 QObject *o = component.create();
5055 QCOMPARE(o->property("test1").toBool(), true);
5056 QCOMPARE(o->property("test2").toBool(), true);
5057 QCOMPARE(o->property("test3").toBool(), true);
5062 // Test the "Qt.include" method
5063 void tst_qdeclarativeecmascript::include()
5065 // Non-library relative include
5067 QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
5068 QObject *o = component.create();
5071 QCOMPARE(o->property("test0").toInt(), 99);
5072 QCOMPARE(o->property("test1").toBool(), true);
5073 QCOMPARE(o->property("test2").toBool(), true);
5074 QCOMPARE(o->property("test2_1").toBool(), true);
5075 QCOMPARE(o->property("test3").toBool(), true);
5076 QCOMPARE(o->property("test3_1").toBool(), true);
5081 // Library relative include
5083 QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
5084 QObject *o = component.create();
5087 QCOMPARE(o->property("test0").toInt(), 99);
5088 QCOMPARE(o->property("test1").toBool(), true);
5089 QCOMPARE(o->property("test2").toBool(), true);
5090 QCOMPARE(o->property("test2_1").toBool(), true);
5091 QCOMPARE(o->property("test3").toBool(), true);
5092 QCOMPARE(o->property("test3_1").toBool(), true);
5099 QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
5100 QObject *o = component.create();
5103 QCOMPARE(o->property("test1").toBool(), true);
5104 QCOMPARE(o->property("test2").toBool(), true);
5105 QCOMPARE(o->property("test3").toBool(), true);
5106 QCOMPARE(o->property("test4").toBool(), true);
5107 QCOMPARE(o->property("test5").toBool(), true);
5108 QCOMPARE(o->property("test6").toBool(), true);
5113 // Including file with ".pragma library"
5115 QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
5116 QObject *o = component.create();
5118 QCOMPARE(o->property("test1").toInt(), 100);
5125 TestHTTPServer server(8111);
5126 QVERIFY(server.isValid());
5127 server.serveDirectory(dataDirectory());
5129 QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
5130 QObject *o = component.create();
5133 QTRY_VERIFY(o->property("done").toBool() == true);
5134 QTRY_VERIFY(o->property("done2").toBool() == true);
5136 QCOMPARE(o->property("test1").toBool(), true);
5137 QCOMPARE(o->property("test2").toBool(), true);
5138 QCOMPARE(o->property("test3").toBool(), true);
5139 QCOMPARE(o->property("test4").toBool(), true);
5140 QCOMPARE(o->property("test5").toBool(), true);
5142 QCOMPARE(o->property("test6").toBool(), true);
5143 QCOMPARE(o->property("test7").toBool(), true);
5144 QCOMPARE(o->property("test8").toBool(), true);
5145 QCOMPARE(o->property("test9").toBool(), true);
5146 QCOMPARE(o->property("test10").toBool(), true);
5153 TestHTTPServer server(8111);
5154 QVERIFY(server.isValid());
5155 server.serveDirectory(dataDirectory());
5157 QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
5158 QObject *o = component.create();
5161 QTRY_VERIFY(o->property("done").toBool() == true);
5163 QCOMPARE(o->property("test1").toBool(), true);
5164 QCOMPARE(o->property("test2").toBool(), true);
5165 QCOMPARE(o->property("test3").toBool(), true);
5171 void tst_qdeclarativeecmascript::signalHandlers()
5173 QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
5174 QObject *o = component.create();
5177 QVERIFY(o->property("count").toInt() == 0);
5178 QMetaObject::invokeMethod(o, "testSignalCall");
5179 QCOMPARE(o->property("count").toInt(), 1);
5181 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5182 QCOMPARE(o->property("count").toInt(), 1);
5183 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5185 QVERIFY(o->property("funcCount").toInt() == 0);
5186 QMetaObject::invokeMethod(o, "testSignalConnection");
5187 QCOMPARE(o->property("funcCount").toInt(), 1);
5189 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5190 QCOMPARE(o->property("funcCount").toInt(), 2);
5192 QMetaObject::invokeMethod(o, "testSignalDefined");
5193 QCOMPARE(o->property("definedResult").toBool(), true);
5195 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5196 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5201 void tst_qdeclarativeecmascript::qtbug_10696()
5203 QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
5204 QObject *o = component.create();
5209 void tst_qdeclarativeecmascript::qtbug_11606()
5211 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
5212 QObject *o = component.create();
5214 QCOMPARE(o->property("test").toBool(), true);
5218 void tst_qdeclarativeecmascript::qtbug_11600()
5220 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
5221 QObject *o = component.create();
5223 QCOMPARE(o->property("test").toBool(), true);
5227 void tst_qdeclarativeecmascript::qtbug_21864()
5229 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
5230 QObject *o = component.create();
5232 QCOMPARE(o->property("test").toBool(), true);
5236 void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
5239 QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
5240 QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
5241 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5242 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5243 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5244 QObject *o = component.create();
5246 QCOMPARE(o->property("test").toBool(), true);
5250 // Reading and writing non-scriptable properties should fail
5251 void tst_qdeclarativeecmascript::nonscriptable()
5253 QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
5254 QObject *o = component.create();
5256 QCOMPARE(o->property("readOk").toBool(), true);
5257 QCOMPARE(o->property("writeOk").toBool(), true);
5261 // deleteLater() should not be callable from QML
5262 void tst_qdeclarativeecmascript::deleteLater()
5264 QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
5265 QObject *o = component.create();
5267 QCOMPARE(o->property("test").toBool(), true);
5271 void tst_qdeclarativeecmascript::in()
5273 QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
5274 QObject *o = component.create();
5276 QCOMPARE(o->property("test1").toBool(), true);
5277 QCOMPARE(o->property("test2").toBool(), true);
5281 void tst_qdeclarativeecmascript::typeOf()
5283 QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
5285 // These warnings should not happen once QTBUG-21864 is fixed
5286 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5287 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5289 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5290 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5292 QObject *o = component.create();
5295 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5296 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5297 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5298 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5299 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5300 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5301 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5302 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5303 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5304 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5309 void tst_qdeclarativeecmascript::sharedAttachedObject()
5311 QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
5312 QObject *o = component.create();
5314 QCOMPARE(o->property("test1").toBool(), true);
5315 QCOMPARE(o->property("test2").toBool(), true);
5320 void tst_qdeclarativeecmascript::objectName()
5322 QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
5323 QObject *o = component.create();
5326 QCOMPARE(o->property("test1").toString(), QString("hello"));
5327 QCOMPARE(o->property("test2").toString(), QString("ell"));
5329 o->setObjectName("world");
5331 QCOMPARE(o->property("test1").toString(), QString("world"));
5332 QCOMPARE(o->property("test2").toString(), QString("orl"));
5337 void tst_qdeclarativeecmascript::writeRemovesBinding()
5339 QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
5340 QObject *o = component.create();
5343 QCOMPARE(o->property("test").toBool(), true);
5348 // Test bindings assigned to alias properties actually assign to the alias' target
5349 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5351 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
5352 QObject *o = component.create();
5355 QCOMPARE(o->property("test").toBool(), true);
5360 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5361 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5364 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
5365 QObject *o = component.create();
5368 QCOMPARE(o->property("test").toBool(), true);
5374 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
5375 QObject *o = component.create();
5378 QCOMPARE(o->property("test").toBool(), true);
5384 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
5385 QObject *o = component.create();
5388 QCOMPARE(o->property("test").toBool(), true);
5394 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5395 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5398 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
5399 QObject *o = component.create();
5402 QCOMPARE(o->property("test").toBool(), true);
5408 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
5409 QObject *o = component.create();
5412 QCOMPARE(o->property("test").toBool(), true);
5418 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
5419 QObject *o = component.create();
5422 QCOMPARE(o->property("test").toBool(), true);
5428 // Allow an alais to a composite element
5430 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5432 QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
5434 QObject *object = component.create();
5435 QVERIFY(object != 0);
5440 void tst_qdeclarativeecmascript::qtbug_20344()
5442 QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
5444 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5445 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5447 QObject *object = component.create();
5448 QVERIFY(object != 0);
5453 void tst_qdeclarativeecmascript::revisionErrors()
5456 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
5457 QString url = component.url().toString();
5459 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5460 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5461 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5463 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5464 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5465 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5466 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5467 QVERIFY(object != 0);
5471 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
5472 QString url = component.url().toString();
5474 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5475 // method2, prop2 from MyRevisionedClass not available
5476 // method4, prop4 from MyRevisionedSubclass not available
5477 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5478 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5479 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5480 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5481 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5483 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5484 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5485 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5486 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5487 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5488 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5489 QVERIFY(object != 0);
5493 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
5494 QString url = component.url().toString();
5496 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5497 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5498 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5499 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5500 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5501 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5502 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5503 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5504 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5505 QVERIFY(object != 0);
5510 void tst_qdeclarativeecmascript::revision()
5513 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
5514 QString url = component.url().toString();
5516 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5517 QVERIFY(object != 0);
5521 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
5522 QString url = component.url().toString();
5524 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5525 QVERIFY(object != 0);
5529 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
5530 QString url = component.url().toString();
5532 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5533 QVERIFY(object != 0);
5536 // Test that non-root classes can resolve revisioned methods
5538 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
5540 QObject *object = component.create();
5541 QVERIFY(object != 0);
5542 QCOMPARE(object->property("test").toReal(), 11.);
5547 void tst_qdeclarativeecmascript::realToInt()
5549 QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
5550 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5551 QVERIFY(object != 0);
5553 QMetaObject::invokeMethod(object, "test1");
5554 QCOMPARE(object->value(), int(4));
5555 QMetaObject::invokeMethod(object, "test2");
5556 QCOMPARE(object->value(), int(8));
5559 void tst_qdeclarativeecmascript::urlProperty()
5562 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
5563 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5564 QVERIFY(object != 0);
5565 object->setStringProperty("http://qt-project.org");
5566 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5567 QCOMPARE(object->intProperty(), 123);
5568 QCOMPARE(object->value(), 1);
5569 QCOMPARE(object->property("result").toBool(), true);
5573 void tst_qdeclarativeecmascript::urlPropertyWithEncoding()
5576 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.2.qml"));
5577 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5578 QVERIFY(object != 0);
5579 object->setStringProperty("http://qt-project.org");
5581 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5582 QCOMPARE(object->urlProperty(), encoded);
5583 QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
5584 QCOMPARE(object->property("result").toBool(), true);
5588 void tst_qdeclarativeecmascript::urlListPropertyWithEncoding()
5591 QDeclarativeComponent component(&engine, testFileUrl("urlListProperty.qml"));
5592 QObject *object = component.create();
5593 QVERIFY(object != 0);
5594 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
5595 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
5596 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
5597 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
5598 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
5600 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5601 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
5602 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
5603 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5604 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5609 void tst_qdeclarativeecmascript::dynamicString()
5611 QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
5612 QObject *object = component.create();
5613 QVERIFY(object != 0);
5614 QCOMPARE(object->property("stringProperty").toString(),
5615 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5618 void tst_qdeclarativeecmascript::automaticSemicolon()
5620 QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
5621 QObject *object = component.create();
5622 QVERIFY(object != 0);
5625 void tst_qdeclarativeecmascript::unaryExpression()
5627 QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
5628 QObject *object = component.create();
5629 QVERIFY(object != 0);
5632 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5633 void tst_qdeclarativeecmascript::doubleEvaluate()
5635 QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
5636 QObject *object = component.create();
5637 QVERIFY(object != 0);
5638 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5640 QCOMPARE(wc->count(), 1);
5642 wc->setProperty("x", 9);
5644 QCOMPARE(wc->count(), 2);
5649 static QStringList messages;
5650 static void captureMsgHandler(QtMsgType, const char *msg)
5652 messages.append(QLatin1String(msg));
5655 void tst_qdeclarativeecmascript::nonNotifyable()
5657 QV4Compiler::enableV4(false);
5658 QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
5659 QV4Compiler::enableV4(true);
5661 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5663 QObject *object = component.create();
5664 qInstallMsgHandler(old);
5666 QVERIFY(object != 0);
5668 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5669 component.url().toString() +
5670 QLatin1String(":5 depends on non-NOTIFYable properties:");
5671 QString expected2 = QLatin1String(" ") +
5672 QLatin1String(object->metaObject()->className()) +
5673 QLatin1String("::value");
5675 QCOMPARE(messages.length(), 2);
5676 QCOMPARE(messages.at(0), expected1);
5677 QCOMPARE(messages.at(1), expected2);
5682 void tst_qdeclarativeecmascript::forInLoop()
5684 QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
5685 QObject *object = component.create();
5686 QVERIFY(object != 0);
5688 QMetaObject::invokeMethod(object, "listProperty");
5690 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5691 QCOMPARE(r.size(), 3);
5692 QCOMPARE(r[0],QLatin1String("0=obj1"));
5693 QCOMPARE(r[1],QLatin1String("1=obj2"));
5694 QCOMPARE(r[2],QLatin1String("2=obj3"));
5696 //TODO: should test for in loop for other objects (such as QObjects) as well.
5701 // An object the binding depends on is deleted while the binding is still running
5702 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5704 QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
5705 QObject *object = component.create();
5706 QVERIFY(object != 0);
5710 void tst_qdeclarativeecmascript::qtbug_22679()
5713 object.setStringProperty(QLatin1String("Please work correctly"));
5714 engine.rootContext()->setContextProperty("contextProp", &object);
5716 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
5717 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5718 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5720 QObject *o = component.create();
5722 QCOMPARE(warningsSpy.count(), 0);
5726 void tst_qdeclarativeecmascript::qtbug_22843_data()
5728 QTest::addColumn<bool>("library");
5730 QTest::newRow("without .pragma library") << false;
5731 QTest::newRow("with .pragma library") << true;
5734 void tst_qdeclarativeecmascript::qtbug_22843()
5736 QFETCH(bool, library);
5738 QString fileName("qtbug_22843");
5740 fileName += QLatin1String(".library");
5741 fileName += QLatin1String(".qml");
5743 QDeclarativeComponent component(&engine, testFileUrl(fileName));
5744 QString url = component.url().toString();
5745 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5746 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5748 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5749 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5750 for (int x = 0; x < 3; ++x) {
5751 warningsSpy.clear();
5752 // For libraries, only the first import attempt should produce a
5753 // SyntaxError warning; subsequent component creation should not
5754 // attempt to reload the script.
5755 bool expectSyntaxError = !library || (x == 0);
5756 if (expectSyntaxError)
5757 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5758 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5759 QObject *object = component.create();
5760 QVERIFY(object != 0);
5761 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5767 void tst_qdeclarativeecmascript::switchStatement()
5770 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
5771 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5772 QVERIFY(object != 0);
5774 // `object->value()' is the number of executed statements
5776 object->setStringProperty("A");
5777 QCOMPARE(object->value(), 5);
5779 object->setStringProperty("S");
5780 QCOMPARE(object->value(), 3);
5782 object->setStringProperty("D");
5783 QCOMPARE(object->value(), 3);
5785 object->setStringProperty("F");
5786 QCOMPARE(object->value(), 4);
5788 object->setStringProperty("something else");
5789 QCOMPARE(object->value(), 1);
5793 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
5794 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5795 QVERIFY(object != 0);
5797 // `object->value()' is the number of executed statements
5799 object->setStringProperty("A");
5800 QCOMPARE(object->value(), 5);
5802 object->setStringProperty("S");
5803 QCOMPARE(object->value(), 3);
5805 object->setStringProperty("D");
5806 QCOMPARE(object->value(), 3);
5808 object->setStringProperty("F");
5809 QCOMPARE(object->value(), 3);
5811 object->setStringProperty("something else");
5812 QCOMPARE(object->value(), 4);
5816 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
5817 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5818 QVERIFY(object != 0);
5820 // `object->value()' is the number of executed statements
5822 object->setStringProperty("A");
5823 QCOMPARE(object->value(), 5);
5825 object->setStringProperty("S");
5826 QCOMPARE(object->value(), 3);
5828 object->setStringProperty("D");
5829 QCOMPARE(object->value(), 3);
5831 object->setStringProperty("F");
5832 QCOMPARE(object->value(), 3);
5834 object->setStringProperty("something else");
5835 QCOMPARE(object->value(), 6);
5839 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
5841 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5842 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5844 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5845 QVERIFY(object != 0);
5847 // `object->value()' is the number of executed statements
5849 object->setStringProperty("A");
5850 QCOMPARE(object->value(), 5);
5852 object->setStringProperty("S");
5853 QCOMPARE(object->value(), 3);
5855 object->setStringProperty("D");
5856 QCOMPARE(object->value(), 3);
5858 object->setStringProperty("F");
5859 QCOMPARE(object->value(), 3);
5861 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5863 object->setStringProperty("something else");
5867 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
5868 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5869 QVERIFY(object != 0);
5871 // `object->value()' is the number of executed statements
5873 object->setStringProperty("A");
5874 QCOMPARE(object->value(), 1);
5876 object->setStringProperty("S");
5877 QCOMPARE(object->value(), 1);
5879 object->setStringProperty("D");
5880 QCOMPARE(object->value(), 1);
5882 object->setStringProperty("F");
5883 QCOMPARE(object->value(), 1);
5885 object->setStringProperty("something else");
5886 QCOMPARE(object->value(), 1);
5890 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
5891 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5892 QVERIFY(object != 0);
5894 // `object->value()' is the number of executed statements
5896 object->setStringProperty("A");
5897 QCOMPARE(object->value(), 123);
5899 object->setStringProperty("S");
5900 QCOMPARE(object->value(), 123);
5902 object->setStringProperty("D");
5903 QCOMPARE(object->value(), 321);
5905 object->setStringProperty("F");
5906 QCOMPARE(object->value(), 321);
5908 object->setStringProperty("something else");
5909 QCOMPARE(object->value(), 0);
5913 void tst_qdeclarativeecmascript::withStatement()
5916 QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
5917 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5918 QVERIFY(object != 0);
5920 QCOMPARE(object->value(), 123);
5924 void tst_qdeclarativeecmascript::tryStatement()
5927 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
5928 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5929 QVERIFY(object != 0);
5931 QCOMPARE(object->value(), 123);
5935 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
5936 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5937 QVERIFY(object != 0);
5939 QCOMPARE(object->value(), 321);
5943 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
5944 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5945 QVERIFY(object != 0);
5947 QCOMPARE(object->value(), 1);
5951 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
5952 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5953 QVERIFY(object != 0);
5955 QCOMPARE(object->value(), 1);
5959 QTEST_MAIN(tst_qdeclarativeecmascript)
5961 #include "tst_qdeclarativeecmascript.moc"