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);
1785 void tst_qdeclarativeecmascript::regExpBug()
1787 QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
1788 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1789 QVERIFY(object != 0);
1790 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1794 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1796 QString functionSource = QLatin1String("(function(object) { return ") +
1797 QLatin1String(source) + QLatin1String(" })");
1799 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1802 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1803 if (function.IsEmpty())
1805 v8::Handle<v8::Value> args[] = { o };
1806 function->Call(engine->global(), 1, args);
1807 return tc.HasCaught();
1810 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1811 const char *source, v8::Handle<v8::Value> result)
1813 QString functionSource = QLatin1String("(function(object) { return ") +
1814 QLatin1String(source) + QLatin1String(" })");
1816 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1819 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1820 if (function.IsEmpty())
1822 v8::Handle<v8::Value> args[] = { o };
1824 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1829 return value->StrictEquals(result);
1832 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1835 QString functionSource = QLatin1String("(function(object) { return ") +
1836 QLatin1String(source) + QLatin1String(" })");
1838 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1840 return v8::Handle<v8::Value>();
1841 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1842 if (function.IsEmpty())
1843 return v8::Handle<v8::Value>();
1844 v8::Handle<v8::Value> args[] = { o };
1846 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1849 return v8::Handle<v8::Value>();
1853 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1854 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1855 #define EVALUATE(source) evaluate(engine, object, source)
1857 void tst_qdeclarativeecmascript::callQtInvokables()
1859 MyInvokableObject o;
1861 QDeclarativeEngine qmlengine;
1862 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1864 QV8Engine *engine = ep->v8engine();
1866 v8::HandleScope handle_scope;
1867 v8::Context::Scope scope(engine->context());
1869 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1871 // Non-existent methods
1873 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1874 QCOMPARE(o.error(), false);
1875 QCOMPARE(o.invoked(), -1);
1876 QCOMPARE(o.actuals().count(), 0);
1879 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1880 QCOMPARE(o.error(), false);
1881 QCOMPARE(o.invoked(), -1);
1882 QCOMPARE(o.actuals().count(), 0);
1884 // Insufficient arguments
1886 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1887 QCOMPARE(o.error(), false);
1888 QCOMPARE(o.invoked(), -1);
1889 QCOMPARE(o.actuals().count(), 0);
1892 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1893 QCOMPARE(o.error(), false);
1894 QCOMPARE(o.invoked(), -1);
1895 QCOMPARE(o.actuals().count(), 0);
1897 // Excessive arguments
1899 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1900 QCOMPARE(o.error(), false);
1901 QCOMPARE(o.invoked(), 8);
1902 QCOMPARE(o.actuals().count(), 1);
1903 QCOMPARE(o.actuals().at(0), QVariant(10));
1906 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1907 QCOMPARE(o.error(), false);
1908 QCOMPARE(o.invoked(), 9);
1909 QCOMPARE(o.actuals().count(), 2);
1910 QCOMPARE(o.actuals().at(0), QVariant(10));
1911 QCOMPARE(o.actuals().at(1), QVariant(11));
1913 // Test return types
1915 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1916 QCOMPARE(o.error(), false);
1917 QCOMPARE(o.invoked(), 0);
1918 QCOMPARE(o.actuals().count(), 0);
1921 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1922 QCOMPARE(o.error(), false);
1923 QCOMPARE(o.invoked(), 1);
1924 QCOMPARE(o.actuals().count(), 0);
1927 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1928 QCOMPARE(o.error(), false);
1929 QCOMPARE(o.invoked(), 2);
1930 QCOMPARE(o.actuals().count(), 0);
1934 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1935 QVERIFY(!ret.IsEmpty());
1936 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1937 QCOMPARE(o.error(), false);
1938 QCOMPARE(o.invoked(), 3);
1939 QCOMPARE(o.actuals().count(), 0);
1944 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1945 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1946 QCOMPARE(o.error(), false);
1947 QCOMPARE(o.invoked(), 4);
1948 QCOMPARE(o.actuals().count(), 0);
1952 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1953 QCOMPARE(o.error(), false);
1954 QCOMPARE(o.invoked(), 5);
1955 QCOMPARE(o.actuals().count(), 0);
1959 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1960 QVERIFY(ret->IsString());
1961 QCOMPARE(engine->toString(ret), QString("Hello world"));
1962 QCOMPARE(o.error(), false);
1963 QCOMPARE(o.invoked(), 6);
1964 QCOMPARE(o.actuals().count(), 0);
1968 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1969 QCOMPARE(o.error(), false);
1970 QCOMPARE(o.invoked(), 7);
1971 QCOMPARE(o.actuals().count(), 0);
1975 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1976 QCOMPARE(o.error(), false);
1977 QCOMPARE(o.invoked(), 8);
1978 QCOMPARE(o.actuals().count(), 1);
1979 QCOMPARE(o.actuals().at(0), QVariant(94));
1982 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1983 QCOMPARE(o.error(), false);
1984 QCOMPARE(o.invoked(), 8);
1985 QCOMPARE(o.actuals().count(), 1);
1986 QCOMPARE(o.actuals().at(0), QVariant(94));
1989 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1990 QCOMPARE(o.error(), false);
1991 QCOMPARE(o.invoked(), 8);
1992 QCOMPARE(o.actuals().count(), 1);
1993 QCOMPARE(o.actuals().at(0), QVariant(0));
1996 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1997 QCOMPARE(o.error(), false);
1998 QCOMPARE(o.invoked(), 8);
1999 QCOMPARE(o.actuals().count(), 1);
2000 QCOMPARE(o.actuals().at(0), QVariant(0));
2003 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
2004 QCOMPARE(o.error(), false);
2005 QCOMPARE(o.invoked(), 8);
2006 QCOMPARE(o.actuals().count(), 1);
2007 QCOMPARE(o.actuals().at(0), QVariant(0));
2010 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2011 QCOMPARE(o.error(), false);
2012 QCOMPARE(o.invoked(), 8);
2013 QCOMPARE(o.actuals().count(), 1);
2014 QCOMPARE(o.actuals().at(0), QVariant(0));
2017 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2018 QCOMPARE(o.error(), false);
2019 QCOMPARE(o.invoked(), 9);
2020 QCOMPARE(o.actuals().count(), 2);
2021 QCOMPARE(o.actuals().at(0), QVariant(122));
2022 QCOMPARE(o.actuals().at(1), QVariant(9));
2025 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2026 QCOMPARE(o.error(), false);
2027 QCOMPARE(o.invoked(), 10);
2028 QCOMPARE(o.actuals().count(), 1);
2029 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2032 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2033 QCOMPARE(o.error(), false);
2034 QCOMPARE(o.invoked(), 10);
2035 QCOMPARE(o.actuals().count(), 1);
2036 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2039 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2040 QCOMPARE(o.error(), false);
2041 QCOMPARE(o.invoked(), 10);
2042 QCOMPARE(o.actuals().count(), 1);
2043 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2046 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2047 QCOMPARE(o.error(), false);
2048 QCOMPARE(o.invoked(), 10);
2049 QCOMPARE(o.actuals().count(), 1);
2050 QCOMPARE(o.actuals().at(0), QVariant(0));
2053 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2054 QCOMPARE(o.error(), false);
2055 QCOMPARE(o.invoked(), 10);
2056 QCOMPARE(o.actuals().count(), 1);
2057 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2060 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2061 QCOMPARE(o.error(), false);
2062 QCOMPARE(o.invoked(), 10);
2063 QCOMPARE(o.actuals().count(), 1);
2064 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2067 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2068 QCOMPARE(o.error(), false);
2069 QCOMPARE(o.invoked(), 11);
2070 QCOMPARE(o.actuals().count(), 1);
2071 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2074 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2075 QCOMPARE(o.error(), false);
2076 QCOMPARE(o.invoked(), 11);
2077 QCOMPARE(o.actuals().count(), 1);
2078 QCOMPARE(o.actuals().at(0), QVariant("19"));
2082 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2083 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2084 QCOMPARE(o.error(), false);
2085 QCOMPARE(o.invoked(), 11);
2086 QCOMPARE(o.actuals().count(), 1);
2087 QCOMPARE(o.actuals().at(0), QVariant(expected));
2091 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2092 QCOMPARE(o.error(), false);
2093 QCOMPARE(o.invoked(), 11);
2094 QCOMPARE(o.actuals().count(), 1);
2095 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2098 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2099 QCOMPARE(o.error(), false);
2100 QCOMPARE(o.invoked(), 11);
2101 QCOMPARE(o.actuals().count(), 1);
2102 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2105 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2106 QCOMPARE(o.error(), false);
2107 QCOMPARE(o.invoked(), 12);
2108 QCOMPARE(o.actuals().count(), 1);
2109 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2112 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2113 QCOMPARE(o.error(), false);
2114 QCOMPARE(o.invoked(), 12);
2115 QCOMPARE(o.actuals().count(), 1);
2116 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2119 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2120 QCOMPARE(o.error(), false);
2121 QCOMPARE(o.invoked(), 12);
2122 QCOMPARE(o.actuals().count(), 1);
2123 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2126 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2127 QCOMPARE(o.error(), false);
2128 QCOMPARE(o.invoked(), 12);
2129 QCOMPARE(o.actuals().count(), 1);
2130 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2133 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2134 QCOMPARE(o.error(), false);
2135 QCOMPARE(o.invoked(), 12);
2136 QCOMPARE(o.actuals().count(), 1);
2137 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2140 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2141 QCOMPARE(o.error(), false);
2142 QCOMPARE(o.invoked(), 12);
2143 QCOMPARE(o.actuals().count(), 1);
2144 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2147 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2148 QCOMPARE(o.error(), false);
2149 QCOMPARE(o.invoked(), 13);
2150 QCOMPARE(o.actuals().count(), 1);
2151 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2154 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2155 QCOMPARE(o.error(), false);
2156 QCOMPARE(o.invoked(), 13);
2157 QCOMPARE(o.actuals().count(), 1);
2158 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2161 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2162 QCOMPARE(o.error(), false);
2163 QCOMPARE(o.invoked(), 13);
2164 QCOMPARE(o.actuals().count(), 1);
2165 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2168 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2169 QCOMPARE(o.error(), false);
2170 QCOMPARE(o.invoked(), 13);
2171 QCOMPARE(o.actuals().count(), 1);
2172 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2175 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2176 QCOMPARE(o.error(), false);
2177 QCOMPARE(o.invoked(), 13);
2178 QCOMPARE(o.actuals().count(), 1);
2179 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2182 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2183 QCOMPARE(o.error(), false);
2184 QCOMPARE(o.invoked(), 14);
2185 QCOMPARE(o.actuals().count(), 1);
2186 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2189 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2190 QCOMPARE(o.error(), false);
2191 QCOMPARE(o.invoked(), 14);
2192 QCOMPARE(o.actuals().count(), 1);
2193 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2196 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2197 QCOMPARE(o.error(), false);
2198 QCOMPARE(o.invoked(), 14);
2199 QCOMPARE(o.actuals().count(), 1);
2200 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2203 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2204 QCOMPARE(o.error(), false);
2205 QCOMPARE(o.invoked(), 14);
2206 QCOMPARE(o.actuals().count(), 1);
2207 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2210 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2211 QCOMPARE(o.error(), false);
2212 QCOMPARE(o.invoked(), 15);
2213 QCOMPARE(o.actuals().count(), 2);
2214 QCOMPARE(o.actuals().at(0), QVariant(4));
2215 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2218 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2219 QCOMPARE(o.error(), false);
2220 QCOMPARE(o.invoked(), 15);
2221 QCOMPARE(o.actuals().count(), 2);
2222 QCOMPARE(o.actuals().at(0), QVariant(8));
2223 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2226 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2227 QCOMPARE(o.error(), false);
2228 QCOMPARE(o.invoked(), 15);
2229 QCOMPARE(o.actuals().count(), 2);
2230 QCOMPARE(o.actuals().at(0), QVariant(3));
2231 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2234 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2235 QCOMPARE(o.error(), false);
2236 QCOMPARE(o.invoked(), 15);
2237 QCOMPARE(o.actuals().count(), 2);
2238 QCOMPARE(o.actuals().at(0), QVariant(44));
2239 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2242 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2243 QCOMPARE(o.error(), false);
2244 QCOMPARE(o.invoked(), -1);
2245 QCOMPARE(o.actuals().count(), 0);
2248 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2249 QCOMPARE(o.error(), false);
2250 QCOMPARE(o.invoked(), 16);
2251 QCOMPARE(o.actuals().count(), 1);
2252 QCOMPARE(o.actuals().at(0), QVariant(10));
2255 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2256 QCOMPARE(o.error(), false);
2257 QCOMPARE(o.invoked(), 17);
2258 QCOMPARE(o.actuals().count(), 2);
2259 QCOMPARE(o.actuals().at(0), QVariant(10));
2260 QCOMPARE(o.actuals().at(1), QVariant(11));
2263 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2264 QCOMPARE(o.error(), false);
2265 QCOMPARE(o.invoked(), 18);
2266 QCOMPARE(o.actuals().count(), 1);
2267 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2270 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2271 QCOMPARE(o.error(), false);
2272 QCOMPARE(o.invoked(), 19);
2273 QCOMPARE(o.actuals().count(), 1);
2274 QCOMPARE(o.actuals().at(0), QVariant(9));
2277 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2278 QCOMPARE(o.error(), false);
2279 QCOMPARE(o.invoked(), 20);
2280 QCOMPARE(o.actuals().count(), 2);
2281 QCOMPARE(o.actuals().at(0), QVariant(10));
2282 QCOMPARE(o.actuals().at(1), QVariant(19));
2285 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2286 QCOMPARE(o.error(), false);
2287 QCOMPARE(o.invoked(), 20);
2288 QCOMPARE(o.actuals().count(), 2);
2289 QCOMPARE(o.actuals().at(0), QVariant(10));
2290 QCOMPARE(o.actuals().at(1), QVariant(13));
2293 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2294 QCOMPARE(o.error(), false);
2295 QCOMPARE(o.invoked(), -3);
2296 QCOMPARE(o.actuals().count(), 1);
2297 QCOMPARE(o.actuals().at(0), QVariant(9));
2300 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2301 QCOMPARE(o.error(), false);
2302 QCOMPARE(o.invoked(), 21);
2303 QCOMPARE(o.actuals().count(), 2);
2304 QCOMPARE(o.actuals().at(0), QVariant(9));
2305 QCOMPARE(o.actuals().at(1), QVariant());
2308 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2309 QCOMPARE(o.error(), false);
2310 QCOMPARE(o.invoked(), 21);
2311 QCOMPARE(o.actuals().count(), 2);
2312 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2313 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2316 // QTBUG-13047 (check that you can pass registered object types as args)
2317 void tst_qdeclarativeecmascript::invokableObjectArg()
2319 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
2321 QObject *o = component.create();
2323 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2325 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2330 // QTBUG-13047 (check that you can return registered object types from methods)
2331 void tst_qdeclarativeecmascript::invokableObjectRet()
2333 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
2335 QObject *o = component.create();
2337 QCOMPARE(o->property("test").toBool(), true);
2342 void tst_qdeclarativeecmascript::listToVariant()
2344 QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
2346 MyQmlContainer container;
2348 QDeclarativeContext context(engine.rootContext());
2349 context.setContextObject(&container);
2351 QObject *object = component.create(&context);
2352 QVERIFY(object != 0);
2354 QVariant v = object->property("test");
2355 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2356 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2362 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2363 void tst_qdeclarativeecmascript::listAssignment()
2365 QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
2366 QObject *obj = component.create();
2367 QCOMPARE(obj->property("list1length").toInt(), 2);
2368 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2369 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2370 QCOMPARE(list1.count(&list1), list2.count(&list2));
2371 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2372 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2377 void tst_qdeclarativeecmascript::multiEngineObject()
2380 obj.setStringProperty("Howdy planet");
2382 QDeclarativeEngine e1;
2383 e1.rootContext()->setContextProperty("thing", &obj);
2384 QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
2386 QDeclarativeEngine e2;
2387 e2.rootContext()->setContextProperty("thing", &obj);
2388 QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
2390 QObject *o1 = c1.create();
2391 QObject *o2 = c2.create();
2393 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2394 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2400 // Test that references to QObjects are cleanup when the object is destroyed
2401 void tst_qdeclarativeecmascript::deletedObject()
2403 QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
2405 QObject *object = component.create();
2407 QCOMPARE(object->property("test1").toBool(), true);
2408 QCOMPARE(object->property("test2").toBool(), true);
2409 QCOMPARE(object->property("test3").toBool(), true);
2410 QCOMPARE(object->property("test4").toBool(), true);
2415 void tst_qdeclarativeecmascript::attachedPropertyScope()
2417 QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
2419 QObject *object = component.create();
2420 QVERIFY(object != 0);
2422 MyQmlAttachedObject *attached =
2423 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2424 QVERIFY(attached != 0);
2426 QCOMPARE(object->property("value2").toInt(), 0);
2428 attached->emitMySignal();
2430 QCOMPARE(object->property("value2").toInt(), 9);
2435 void tst_qdeclarativeecmascript::scriptConnect()
2438 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
2440 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2441 QVERIFY(object != 0);
2443 QCOMPARE(object->property("test").toBool(), false);
2444 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2445 QCOMPARE(object->property("test").toBool(), true);
2451 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
2453 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2454 QVERIFY(object != 0);
2456 QCOMPARE(object->property("test").toBool(), false);
2457 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2458 QCOMPARE(object->property("test").toBool(), true);
2464 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
2466 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2467 QVERIFY(object != 0);
2469 QCOMPARE(object->property("test").toBool(), false);
2470 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2471 QCOMPARE(object->property("test").toBool(), true);
2477 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
2479 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2480 QVERIFY(object != 0);
2482 QCOMPARE(object->methodCalled(), false);
2483 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2484 QCOMPARE(object->methodCalled(), true);
2490 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
2492 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2493 QVERIFY(object != 0);
2495 QCOMPARE(object->methodCalled(), false);
2496 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2497 QCOMPARE(object->methodCalled(), true);
2503 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
2505 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2506 QVERIFY(object != 0);
2508 QCOMPARE(object->property("test").toInt(), 0);
2509 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2510 QCOMPARE(object->property("test").toInt(), 2);
2516 void tst_qdeclarativeecmascript::scriptDisconnect()
2519 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
2521 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2522 QVERIFY(object != 0);
2524 QCOMPARE(object->property("test").toInt(), 0);
2525 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2526 QCOMPARE(object->property("test").toInt(), 1);
2527 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2528 QCOMPARE(object->property("test").toInt(), 2);
2529 emit object->basicSignal();
2530 QCOMPARE(object->property("test").toInt(), 2);
2531 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2532 QCOMPARE(object->property("test").toInt(), 2);
2538 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
2540 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2541 QVERIFY(object != 0);
2543 QCOMPARE(object->property("test").toInt(), 0);
2544 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2545 QCOMPARE(object->property("test").toInt(), 1);
2546 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2547 QCOMPARE(object->property("test").toInt(), 2);
2548 emit object->basicSignal();
2549 QCOMPARE(object->property("test").toInt(), 2);
2550 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2551 QCOMPARE(object->property("test").toInt(), 2);
2557 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
2559 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2560 QVERIFY(object != 0);
2562 QCOMPARE(object->property("test").toInt(), 0);
2563 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2564 QCOMPARE(object->property("test").toInt(), 1);
2565 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2566 QCOMPARE(object->property("test").toInt(), 2);
2567 emit object->basicSignal();
2568 QCOMPARE(object->property("test").toInt(), 2);
2569 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2570 QCOMPARE(object->property("test").toInt(), 3);
2575 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
2577 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2578 QVERIFY(object != 0);
2580 QCOMPARE(object->property("test").toInt(), 0);
2581 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2582 QCOMPARE(object->property("test").toInt(), 1);
2583 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2584 QCOMPARE(object->property("test").toInt(), 2);
2585 emit object->basicSignal();
2586 QCOMPARE(object->property("test").toInt(), 2);
2587 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2588 QCOMPARE(object->property("test").toInt(), 3);
2594 class OwnershipObject : public QObject
2598 OwnershipObject() { object = new QObject; }
2600 QPointer<QObject> object;
2603 QObject *getObject() { return object; }
2606 void tst_qdeclarativeecmascript::ownership()
2608 OwnershipObject own;
2609 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2610 context->setContextObject(&own);
2613 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2615 QVERIFY(own.object != 0);
2617 QObject *object = component.create(context);
2619 engine.collectGarbage();
2621 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2622 QCoreApplication::processEvents();
2624 QVERIFY(own.object == 0);
2629 own.object = new QObject(&own);
2632 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2634 QVERIFY(own.object != 0);
2636 QObject *object = component.create(context);
2638 engine.collectGarbage();
2640 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2641 QCoreApplication::processEvents();
2643 QVERIFY(own.object != 0);
2651 class CppOwnershipReturnValue : public QObject
2655 CppOwnershipReturnValue() : value(0) {}
2656 ~CppOwnershipReturnValue() { delete value; }
2658 Q_INVOKABLE QObject *create() {
2659 value = new QObject;
2660 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2664 Q_INVOKABLE MyQmlObject *createQmlObject() {
2665 MyQmlObject *rv = new MyQmlObject;
2670 QPointer<QObject> value;
2674 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2675 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2677 CppOwnershipReturnValue source;
2680 QDeclarativeEngine engine;
2681 engine.rootContext()->setContextProperty("source", &source);
2683 QVERIFY(source.value == 0);
2685 QDeclarativeComponent component(&engine);
2686 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2688 QObject *object = component.create();
2690 QVERIFY(object != 0);
2691 QVERIFY(source.value != 0);
2696 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2697 QCoreApplication::processEvents();
2699 QVERIFY(source.value != 0);
2703 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2705 CppOwnershipReturnValue source;
2708 QDeclarativeEngine engine;
2709 engine.rootContext()->setContextProperty("source", &source);
2711 QVERIFY(source.value == 0);
2713 QDeclarativeComponent component(&engine);
2714 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2716 QObject *object = component.create();
2718 QVERIFY(object != 0);
2719 QVERIFY(source.value != 0);
2724 engine.collectGarbage();
2725 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2726 QCoreApplication::processEvents();
2728 QVERIFY(source.value == 0);
2731 class QListQObjectMethodsObject : public QObject
2735 QListQObjectMethodsObject() {
2736 m_objects.append(new MyQmlObject());
2737 m_objects.append(new MyQmlObject());
2740 ~QListQObjectMethodsObject() {
2741 qDeleteAll(m_objects);
2745 QList<QObject *> getObjects() { return m_objects; }
2748 QList<QObject *> m_objects;
2751 // Tests that returning a QList<QObject*> from a method works
2752 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2754 QListQObjectMethodsObject obj;
2755 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2756 context->setContextObject(&obj);
2758 QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
2760 QObject *object = component.create(context);
2762 QCOMPARE(object->property("test").toInt(), 2);
2763 QCOMPARE(object->property("test2").toBool(), true);
2770 void tst_qdeclarativeecmascript::strictlyEquals()
2772 QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
2774 QObject *object = component.create();
2775 QVERIFY(object != 0);
2777 QCOMPARE(object->property("test1").toBool(), true);
2778 QCOMPARE(object->property("test2").toBool(), true);
2779 QCOMPARE(object->property("test3").toBool(), true);
2780 QCOMPARE(object->property("test4").toBool(), true);
2781 QCOMPARE(object->property("test5").toBool(), true);
2782 QCOMPARE(object->property("test6").toBool(), true);
2783 QCOMPARE(object->property("test7").toBool(), true);
2784 QCOMPARE(object->property("test8").toBool(), true);
2789 void tst_qdeclarativeecmascript::compiled()
2791 QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
2793 QObject *object = component.create();
2794 QVERIFY(object != 0);
2796 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2797 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2798 QCOMPARE(object->property("test3").toBool(), true);
2799 QCOMPARE(object->property("test4").toBool(), false);
2800 QCOMPARE(object->property("test5").toBool(), false);
2801 QCOMPARE(object->property("test6").toBool(), true);
2803 QCOMPARE(object->property("test7").toInt(), 185);
2804 QCOMPARE(object->property("test8").toInt(), 167);
2805 QCOMPARE(object->property("test9").toBool(), true);
2806 QCOMPARE(object->property("test10").toBool(), false);
2807 QCOMPARE(object->property("test11").toBool(), false);
2808 QCOMPARE(object->property("test12").toBool(), true);
2810 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2811 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2812 QCOMPARE(object->property("test15").toBool(), false);
2813 QCOMPARE(object->property("test16").toBool(), true);
2815 QCOMPARE(object->property("test17").toInt(), 5);
2816 QCOMPARE(object->property("test18").toReal(), qreal(176));
2817 QCOMPARE(object->property("test19").toInt(), 7);
2818 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2819 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2820 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2821 QCOMPARE(object->property("test23").toBool(), true);
2822 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2823 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2828 // Test that numbers assigned in bindings as strings work consistently
2829 void tst_qdeclarativeecmascript::numberAssignment()
2831 QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
2833 QObject *object = component.create();
2834 QVERIFY(object != 0);
2836 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2837 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2838 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2839 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2840 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2842 QCOMPARE(object->property("test5"), QVariant((int)7));
2843 QCOMPARE(object->property("test6"), QVariant((int)7));
2844 QCOMPARE(object->property("test7"), QVariant((int)6));
2845 QCOMPARE(object->property("test8"), QVariant((int)6));
2847 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2848 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2849 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2850 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2855 void tst_qdeclarativeecmascript::propertySplicing()
2857 QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
2859 QObject *object = component.create();
2860 QVERIFY(object != 0);
2862 QCOMPARE(object->property("test").toBool(), true);
2868 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2870 QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
2872 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2873 QVERIFY(object != 0);
2875 MyQmlObject::MyType type;
2876 type.value = 0x8971123;
2877 emit object->signalWithUnknownType(type);
2879 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2881 QCOMPARE(result.value, type.value);
2887 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2889 QTest::addColumn<QString>("expression");
2890 QTest::addColumn<QString>("compare");
2892 QString compareStrict("(function(a, b) { return a === b; })");
2893 QTest::newRow("true") << "true" << compareStrict;
2894 QTest::newRow("undefined") << "undefined" << compareStrict;
2895 QTest::newRow("null") << "null" << compareStrict;
2896 QTest::newRow("123") << "123" << compareStrict;
2897 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2899 QString comparePropertiesStrict(
2901 " if (typeof b != 'object')"
2903 " var props = Object.getOwnPropertyNames(b);"
2904 " for (var i = 0; i < props.length; ++i) {"
2905 " var p = props[i];"
2906 " return arguments.callee(a[p], b[p]);"
2909 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2910 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2913 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2915 QFETCH(QString, expression);
2916 QFETCH(QString, compare);
2918 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2919 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2920 QVERIFY(object != 0);
2922 QJSValue value = engine.evaluate(expression);
2923 QVERIFY(!engine.hasUncaughtException());
2924 object->setProperty("expression", expression);
2925 object->setProperty("compare", compare);
2926 object->setProperty("pass", false);
2928 emit object->signalWithVariant(QVariant::fromValue(value));
2929 QVERIFY(object->property("pass").toBool());
2932 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2934 signalWithJSValueInVariant_data();
2937 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2939 QFETCH(QString, expression);
2940 QFETCH(QString, compare);
2942 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2943 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2944 QVERIFY(object != 0);
2947 QJSValue value = engine2.evaluate(expression);
2948 QVERIFY(!engine2.hasUncaughtException());
2949 object->setProperty("expression", expression);
2950 object->setProperty("compare", compare);
2951 object->setProperty("pass", false);
2953 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2954 emit object->signalWithVariant(QVariant::fromValue(value));
2955 QVERIFY(!object->property("pass").toBool());
2958 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2960 signalWithJSValueInVariant_data();
2963 void tst_qdeclarativeecmascript::signalWithQJSValue()
2965 QFETCH(QString, expression);
2966 QFETCH(QString, compare);
2968 QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
2969 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2970 QVERIFY(object != 0);
2972 QJSValue value = engine.evaluate(expression);
2973 QVERIFY(!engine.hasUncaughtException());
2974 object->setProperty("expression", expression);
2975 object->setProperty("compare", compare);
2976 object->setProperty("pass", false);
2978 emit object->signalWithQJSValue(value);
2980 QVERIFY(object->property("pass").toBool());
2981 QVERIFY(object->qjsvalue().strictlyEquals(value));
2984 void tst_qdeclarativeecmascript::moduleApi_data()
2986 QTest::addColumn<QUrl>("testfile");
2987 QTest::addColumn<QString>("errorMessage");
2988 QTest::addColumn<QStringList>("warningMessages");
2989 QTest::addColumn<QStringList>("readProperties");
2990 QTest::addColumn<QVariantList>("readExpectedValues");
2991 QTest::addColumn<QStringList>("writeProperties");
2992 QTest::addColumn<QVariantList>("writeValues");
2993 QTest::addColumn<QStringList>("readBackProperties");
2994 QTest::addColumn<QVariantList>("readBackExpectedValues");
2996 QTest::newRow("qobject, register + read + method")
2997 << testFileUrl("moduleapi/qobjectModuleApi.qml")
3000 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
3001 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
3002 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
3008 QTest::newRow("script, register + read")
3009 << testFileUrl("moduleapi/scriptModuleApi.qml")
3012 << (QStringList() << "scriptTest")
3013 << (QVariantList() << 13)
3019 QTest::newRow("qobject, caching + read")
3020 << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
3023 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3024 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3030 QTest::newRow("script, caching + read")
3031 << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
3034 << (QStringList() << "scriptTest")
3035 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3041 QTest::newRow("qobject, writing + readonly constraints")
3042 << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
3044 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3045 << (QStringList() << "readOnlyProperty" << "writableProperty")
3046 << (QVariantList() << 20 << 50)
3047 << (QStringList() << "firstProperty" << "writableProperty")
3048 << (QVariantList() << 30 << 30)
3049 << (QStringList() << "readOnlyProperty" << "writableProperty")
3050 << (QVariantList() << 20 << 30);
3052 QTest::newRow("script, writing + readonly constraints")
3053 << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
3055 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3056 << (QStringList() << "readBack" << "unchanged")
3057 << (QVariantList() << 13 << 42)
3058 << (QStringList() << "firstProperty" << "secondProperty")
3059 << (QVariantList() << 30 << 30)
3060 << (QStringList() << "readBack" << "unchanged")
3061 << (QVariantList() << 30 << 42);
3063 QTest::newRow("qobject module API enum values in JS")
3064 << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
3067 << (QStringList() << "enumValue" << "enumMethod")
3068 << (QVariantList() << 42 << 30)
3074 QTest::newRow("qobject, invalid major version fail")
3075 << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
3076 << QString("QDeclarativeComponent: Component is not ready")
3085 QTest::newRow("qobject, invalid minor version fail")
3086 << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
3087 << QString("QDeclarativeComponent: Component is not ready")
3097 void tst_qdeclarativeecmascript::moduleApi()
3099 QFETCH(QUrl, testfile);
3100 QFETCH(QString, errorMessage);
3101 QFETCH(QStringList, warningMessages);
3102 QFETCH(QStringList, readProperties);
3103 QFETCH(QVariantList, readExpectedValues);
3104 QFETCH(QStringList, writeProperties);
3105 QFETCH(QVariantList, writeValues);
3106 QFETCH(QStringList, readBackProperties);
3107 QFETCH(QVariantList, readBackExpectedValues);
3109 QDeclarativeComponent component(&engine, testfile);
3111 if (!errorMessage.isEmpty())
3112 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3114 if (warningMessages.size())
3115 foreach (const QString &warning, warningMessages)
3116 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3118 QObject *object = component.create();
3119 if (!errorMessage.isEmpty()) {
3120 QVERIFY(object == 0);
3122 QVERIFY(object != 0);
3123 for (int i = 0; i < readProperties.size(); ++i)
3124 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3125 for (int i = 0; i < writeProperties.size(); ++i)
3126 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3127 for (int i = 0; i < readBackProperties.size(); ++i)
3128 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3133 void tst_qdeclarativeecmascript::importScripts_data()
3135 QTest::addColumn<QUrl>("testfile");
3136 QTest::addColumn<QString>("errorMessage");
3137 QTest::addColumn<QStringList>("warningMessages");
3138 QTest::addColumn<QStringList>("propertyNames");
3139 QTest::addColumn<QVariantList>("propertyValues");
3141 QTest::newRow("basic functionality")
3142 << testFileUrl("jsimport/testImport.qml")
3145 << (QStringList() << QLatin1String("importedScriptStringValue")
3146 << QLatin1String("importedScriptFunctionValue")
3147 << QLatin1String("importedModuleAttachedPropertyValue")
3148 << QLatin1String("importedModuleEnumValue"))
3149 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3154 QTest::newRow("import scoping")
3155 << testFileUrl("jsimport/testImportScoping.qml")
3158 << (QStringList() << QLatin1String("componentError"))
3159 << (QVariantList() << QVariant(5));
3161 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3162 << testFileUrl("jsimportfail/failOne.qml")
3164 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3165 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3166 << (QVariantList() << QVariant(QString()));
3168 QTest::newRow("javascript imports in an import should be private to the import scope")
3169 << testFileUrl("jsimportfail/failTwo.qml")
3171 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3172 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3173 << (QVariantList() << QVariant(QString()));
3175 QTest::newRow("module imports in an import should be private to the import scope")
3176 << testFileUrl("jsimportfail/failThree.qml")
3178 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3179 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3180 << (QVariantList() << QVariant(false));
3182 QTest::newRow("typenames in an import should be private to the import scope")
3183 << testFileUrl("jsimportfail/failFour.qml")
3185 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3186 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3187 << (QVariantList() << QVariant(0));
3189 QTest::newRow("import with imports has it's own activation scope")
3190 << testFileUrl("jsimportfail/failFive.qml")
3192 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3193 << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3194 << (QStringList() << QLatin1String("componentError"))
3195 << (QVariantList() << QVariant(0));
3197 QTest::newRow("import pragma library script")
3198 << testFileUrl("jsimport/testImportPragmaLibrary.qml")
3201 << (QStringList() << QLatin1String("testValue"))
3202 << (QVariantList() << QVariant(31));
3204 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3205 << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
3208 << (QStringList() << QLatin1String("testValue"))
3209 << (QVariantList() << QVariant(0));
3211 QTest::newRow("import pragma library script which has an import")
3212 << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
3215 << (QStringList() << QLatin1String("testValue"))
3216 << (QVariantList() << QVariant(55));
3218 QTest::newRow("import pragma library script which has a pragma library import")
3219 << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3222 << (QStringList() << QLatin1String("testValue"))
3223 << (QVariantList() << QVariant(18));
3226 void tst_qdeclarativeecmascript::importScripts()
3228 QFETCH(QUrl, testfile);
3229 QFETCH(QString, errorMessage);
3230 QFETCH(QStringList, warningMessages);
3231 QFETCH(QStringList, propertyNames);
3232 QFETCH(QVariantList, propertyValues);
3234 QDeclarativeComponent component(&engine, testfile);
3236 if (!errorMessage.isEmpty())
3237 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3239 if (warningMessages.size())
3240 foreach (const QString &warning, warningMessages)
3241 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3243 QObject *object = component.create();
3244 if (!errorMessage.isEmpty()) {
3245 QVERIFY(object == 0);
3247 QVERIFY(object != 0);
3248 for (int i = 0; i < propertyNames.size(); ++i)
3249 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3254 void tst_qdeclarativeecmascript::scarceResources_other()
3256 /* These tests require knowledge of state, since we test values after
3257 performing signal or function invocation. */
3259 QPixmap origPixmap(100, 100);
3260 origPixmap.fill(Qt::blue);
3261 QString srp_name, expectedWarning;
3262 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3263 ScarceResourceObject *eo = 0;
3265 QObject *object = 0;
3267 /* property var semantics */
3269 // test that scarce resources are handled properly in signal invocation
3270 QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
3271 object = varComponentTen.create();
3272 srsc = object->findChild<QObject*>("srsc");
3274 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3275 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3276 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3277 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3278 QMetaObject::invokeMethod(srsc, "testSignal");
3279 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3280 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3281 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3282 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3283 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3284 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3285 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3286 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3287 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3288 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3291 // test that scarce resources are handled properly from js functions in qml files
3292 QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
3293 object = varComponentEleven.create();
3294 QVERIFY(object != 0);
3295 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3296 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3297 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3298 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3299 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3300 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3301 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3302 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3303 QMetaObject::invokeMethod(object, "releaseScarceResource");
3304 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3305 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3306 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3307 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3310 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3311 QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
3312 object = varComponentTwelve.create();
3313 QVERIFY(object != 0);
3314 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3315 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3316 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3317 srp_name = object->property("srp_name").toString();
3318 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3319 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3320 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3321 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3322 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3323 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3324 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3327 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3328 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3329 QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
3330 object = varComponentThirteen.create();
3331 QVERIFY(object != 0);
3332 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3333 QMetaObject::invokeMethod(object, "assignVarProperty");
3334 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3335 QMetaObject::invokeMethod(object, "deassignVarProperty");
3336 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3339 /* property variant semantics */
3341 // test that scarce resources are handled properly in signal invocation
3342 QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
3343 object = variantComponentTen.create();
3344 QVERIFY(object != 0);
3345 srsc = object->findChild<QObject*>("srsc");
3347 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3348 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3349 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3350 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3351 QMetaObject::invokeMethod(srsc, "testSignal");
3352 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3353 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3354 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3355 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3356 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3357 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3358 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3359 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3360 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3361 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3364 // test that scarce resources are handled properly from js functions in qml files
3365 QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
3366 object = variantComponentEleven.create();
3367 QVERIFY(object != 0);
3368 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3369 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3370 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3371 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3372 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3373 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3374 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3375 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3376 QMetaObject::invokeMethod(object, "releaseScarceResource");
3377 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3378 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3379 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3380 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3383 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3384 QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
3385 object = variantComponentTwelve.create();
3386 QVERIFY(object != 0);
3387 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3388 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3389 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3390 srp_name = object->property("srp_name").toString();
3391 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3392 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3393 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3394 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3395 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3396 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3397 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3401 void tst_qdeclarativeecmascript::scarceResources_data()
3403 QTest::addColumn<QUrl>("qmlFile");
3404 QTest::addColumn<bool>("readDetachStatus");
3405 QTest::addColumn<bool>("expectedDetachStatus");
3406 QTest::addColumn<QStringList>("propertyNames");
3407 QTest::addColumn<QVariantList>("expectedValidity");
3408 QTest::addColumn<QVariantList>("expectedValues");
3409 QTest::addColumn<QStringList>("expectedErrors");
3411 QPixmap origPixmap(100, 100);
3412 origPixmap.fill(Qt::blue);
3414 /* property var semantics */
3416 // in the following three cases, the instance created from the component
3417 // has a property which is a copy of the scarce resource; hence, the
3418 // resource should NOT be detached prior to deletion of the object instance,
3419 // unless the resource is destroyed explicitly.
3420 QTest::newRow("var: import scarce resource copy directly")
3421 << testFileUrl("scarceResourceCopy.var.qml")
3423 << false // won't be detached, because assigned to property and not explicitly released
3424 << (QStringList() << QLatin1String("scarceResourceCopy"))
3425 << (QList<QVariant>() << true)
3426 << (QList<QVariant>() << origPixmap)
3429 QTest::newRow("var: import scarce resource copy from JS")
3430 << testFileUrl("scarceResourceCopyFromJs.var.qml")
3432 << false // won't be detached, because assigned to property and not explicitly released
3433 << (QStringList() << QLatin1String("scarceResourceCopy"))
3434 << (QList<QVariant>() << true)
3435 << (QList<QVariant>() << origPixmap)
3438 QTest::newRow("var: import released scarce resource copy from JS")
3439 << testFileUrl("scarceResourceDestroyedCopy.var.qml")
3441 << true // explicitly released, so it will be detached
3442 << (QStringList() << QLatin1String("scarceResourceCopy"))
3443 << (QList<QVariant>() << false)
3444 << (QList<QVariant>() << QVariant())
3447 // in the following three cases, no other copy should exist in memory,
3448 // and so it should be detached (unless explicitly preserved).
3449 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3450 << testFileUrl("scarceResourceTest.var.qml")
3452 << true // auto released, so it will be detached
3453 << (QStringList() << QLatin1String("scarceResourceTest"))
3454 << (QList<QVariant>() << true)
3455 << (QList<QVariant>() << QVariant(100))
3457 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3458 << testFileUrl("scarceResourceTestPreserve.var.qml")
3460 << false // won't be detached because we explicitly preserve it
3461 << (QStringList() << QLatin1String("scarceResourceTest"))
3462 << (QList<QVariant>() << true)
3463 << (QList<QVariant>() << QVariant(100))
3465 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3466 << testFileUrl("scarceResourceTestMultiple.var.qml")
3468 << true // will be detached because all resources were released manually or automatically.
3469 << (QStringList() << QLatin1String("scarceResourceTest"))
3470 << (QList<QVariant>() << true)
3471 << (QList<QVariant>() << QVariant(100))
3474 // In the following three cases, test that scarce resources are handled
3475 // correctly for imports.
3476 QTest::newRow("var: import with no binding")
3477 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3478 << false // cannot check detach status.
3481 << QList<QVariant>()
3482 << QList<QVariant>()
3484 QTest::newRow("var: import with binding without explicit preserve")
3485 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3488 << (QStringList() << QLatin1String("scarceResourceCopy"))
3489 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3490 << (QList<QVariant>() << QVariant())
3492 QTest::newRow("var: import with explicit release after binding evaluation")
3493 << testFileUrl("scarceResourceCopyImport.var.qml")
3496 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3497 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3498 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3500 QTest::newRow("var: import with different js objects")
3501 << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
3504 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3505 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3506 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3508 QTest::newRow("var: import with different js objects and explicit release")
3509 << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
3512 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3513 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3514 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3516 QTest::newRow("var: import with same js objects and explicit release")
3517 << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
3520 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3521 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3522 << (QList<QVariant>() << QVariant() << QVariant())
3524 QTest::newRow("var: binding with same js objects and explicit release")
3525 << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
3528 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3529 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3530 << (QList<QVariant>() << QVariant() << QVariant())
3534 /* property variant semantics */
3536 // in the following three cases, the instance created from the component
3537 // has a property which is a copy of the scarce resource; hence, the
3538 // resource should NOT be detached prior to deletion of the object instance,
3539 // unless the resource is destroyed explicitly.
3540 QTest::newRow("variant: import scarce resource copy directly")
3541 << testFileUrl("scarceResourceCopy.variant.qml")
3543 << false // won't be detached, because assigned to property and not explicitly released
3544 << (QStringList() << QLatin1String("scarceResourceCopy"))
3545 << (QList<QVariant>() << true)
3546 << (QList<QVariant>() << origPixmap)
3549 QTest::newRow("variant: import scarce resource copy from JS")
3550 << testFileUrl("scarceResourceCopyFromJs.variant.qml")
3552 << false // won't be detached, because assigned to property and not explicitly released
3553 << (QStringList() << QLatin1String("scarceResourceCopy"))
3554 << (QList<QVariant>() << true)
3555 << (QList<QVariant>() << origPixmap)
3558 QTest::newRow("variant: import released scarce resource copy from JS")
3559 << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
3561 << true // explicitly released, so it will be detached
3562 << (QStringList() << QLatin1String("scarceResourceCopy"))
3563 << (QList<QVariant>() << false)
3564 << (QList<QVariant>() << QVariant())
3567 // in the following three cases, no other copy should exist in memory,
3568 // and so it should be detached (unless explicitly preserved).
3569 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3570 << testFileUrl("scarceResourceTest.variant.qml")
3572 << true // auto released, so it will be detached
3573 << (QStringList() << QLatin1String("scarceResourceTest"))
3574 << (QList<QVariant>() << true)
3575 << (QList<QVariant>() << QVariant(100))
3577 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3578 << testFileUrl("scarceResourceTestPreserve.variant.qml")
3580 << false // won't be detached because we explicitly preserve it
3581 << (QStringList() << QLatin1String("scarceResourceTest"))
3582 << (QList<QVariant>() << true)
3583 << (QList<QVariant>() << QVariant(100))
3585 QTest::newRow("variant: import multiple scarce resources")
3586 << testFileUrl("scarceResourceTestMultiple.variant.qml")
3588 << true // will be detached because all resources were released manually or automatically.
3589 << (QStringList() << QLatin1String("scarceResourceTest"))
3590 << (QList<QVariant>() << true)
3591 << (QList<QVariant>() << QVariant(100))
3594 // In the following three cases, test that scarce resources are handled
3595 // correctly for imports.
3596 QTest::newRow("variant: import with no binding")
3597 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3598 << false // cannot check detach status.
3601 << QList<QVariant>()
3602 << QList<QVariant>()
3604 QTest::newRow("variant: import with binding without explicit preserve")
3605 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3608 << (QStringList() << QLatin1String("scarceResourceCopy"))
3609 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3610 << (QList<QVariant>() << QVariant())
3612 QTest::newRow("variant: import with explicit release after binding evaluation")
3613 << testFileUrl("scarceResourceCopyImport.variant.qml")
3616 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3617 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3618 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3622 void tst_qdeclarativeecmascript::scarceResources()
3624 QFETCH(QUrl, qmlFile);
3625 QFETCH(bool, readDetachStatus);
3626 QFETCH(bool, expectedDetachStatus);
3627 QFETCH(QStringList, propertyNames);
3628 QFETCH(QVariantList, expectedValidity);
3629 QFETCH(QVariantList, expectedValues);
3630 QFETCH(QStringList, expectedErrors);
3632 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3633 ScarceResourceObject *eo = 0;
3634 QObject *object = 0;
3636 QDeclarativeComponent c(&engine, qmlFile);
3637 object = c.create();
3638 QVERIFY(object != 0);
3639 for (int i = 0; i < propertyNames.size(); ++i) {
3640 QString prop = propertyNames.at(i);
3641 bool validity = expectedValidity.at(i).toBool();
3642 QVariant value = expectedValues.at(i);
3644 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3645 if (value.type() == QVariant::Int) {
3646 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3647 } else if (value.type() == QVariant::Pixmap) {
3648 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3652 if (readDetachStatus) {
3653 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3654 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3657 QVERIFY(ep->scarceResources.isEmpty());
3661 void tst_qdeclarativeecmascript::propertyChangeSlots()
3663 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3664 QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
3665 QObject *object = component.create();
3666 QVERIFY(object != 0);
3669 // ensure that invalid property names fail properly.
3670 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3671 QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
3672 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3673 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3674 object = e1.create();
3675 QVERIFY(object == 0);
3678 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3679 QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
3680 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3681 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3682 object = e2.create();
3683 QVERIFY(object == 0);
3686 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3687 QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
3688 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3689 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3690 object = e3.create();
3691 QVERIFY(object == 0);
3694 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3695 QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
3696 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3697 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3698 object = e4.create();
3699 QVERIFY(object == 0);
3703 void tst_qdeclarativeecmascript::propertyVar_data()
3705 QTest::addColumn<QUrl>("qmlFile");
3708 QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
3709 QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
3710 QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
3711 QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
3712 QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
3713 QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
3714 QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
3715 QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
3716 QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
3717 QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
3720 void tst_qdeclarativeecmascript::propertyVar()
3722 QFETCH(QUrl, qmlFile);
3724 QDeclarativeComponent component(&engine, qmlFile);
3725 QObject *object = component.create();
3726 QVERIFY(object != 0);
3728 QCOMPARE(object->property("test").toBool(), true);
3733 // Tests that we can write QVariant values to var properties from C++
3734 void tst_qdeclarativeecmascript::propertyVarCpp()
3736 QObject *object = 0;
3738 // ensure that writing to and reading from a var property from cpp works as required.
3739 // Literal values stored in var properties can be read and written as QVariants
3740 // of a specific type, whereas object values are read as QVariantMaps.
3741 QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
3742 object = component.create();
3743 QVERIFY(object != 0);
3744 // assign int to property var that currently has int assigned
3745 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3746 QCOMPARE(object->property("varBound"), QVariant(15));
3747 QCOMPARE(object->property("intBound"), QVariant(15));
3748 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3749 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3750 // assign string to property var that current has bool assigned
3751 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3752 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3753 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3754 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3755 // now enforce behaviour when accessing JavaScript objects from cpp.
3756 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3760 static void gc(QDeclarativeEngine &engine)
3762 engine.collectGarbage();
3763 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
3764 QCoreApplication::processEvents();
3767 void tst_qdeclarativeecmascript::propertyVarOwnership()
3769 // Referenced JS objects are not collected
3771 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
3772 QObject *object = component.create();
3773 QVERIFY(object != 0);
3774 QCOMPARE(object->property("test").toBool(), false);
3775 QMetaObject::invokeMethod(object, "runTest");
3776 QCOMPARE(object->property("test").toBool(), true);
3779 // Referenced JS objects are not collected
3781 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
3782 QObject *object = component.create();
3783 QVERIFY(object != 0);
3784 QCOMPARE(object->property("test").toBool(), false);
3785 QMetaObject::invokeMethod(object, "runTest");
3786 QCOMPARE(object->property("test").toBool(), true);
3789 // Qt objects are not collected until they've been dereferenced
3791 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
3792 QObject *object = component.create();
3793 QVERIFY(object != 0);
3795 QCOMPARE(object->property("test2").toBool(), false);
3796 QCOMPARE(object->property("test2").toBool(), false);
3798 QMetaObject::invokeMethod(object, "runTest");
3799 QCOMPARE(object->property("test1").toBool(), true);
3801 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3802 QVERIFY(!referencedObject.isNull());
3804 QVERIFY(!referencedObject.isNull());
3806 QMetaObject::invokeMethod(object, "runTest2");
3807 QCOMPARE(object->property("test2").toBool(), true);
3809 QVERIFY(referencedObject.isNull());
3813 // Self reference does not prevent Qt object collection
3815 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
3816 QObject *object = component.create();
3817 QVERIFY(object != 0);
3819 QCOMPARE(object->property("test").toBool(), true);
3821 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3822 QVERIFY(!referencedObject.isNull());
3824 QVERIFY(!referencedObject.isNull());
3826 QMetaObject::invokeMethod(object, "runTest");
3828 QVERIFY(referencedObject.isNull());
3834 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3836 // The childObject has a reference to a different QObject. We want to ensure
3837 // that the different item will not be cleaned up until required. IE, the childObject
3838 // has implicit ownership of the constructed QObject.
3839 QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
3840 QObject *object = component.create();
3841 QVERIFY(object != 0);
3842 QMetaObject::invokeMethod(object, "assignCircular");
3843 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3844 QCoreApplication::processEvents();
3845 QObject *rootObject = object->property("vp").value<QObject*>();
3846 QVERIFY(rootObject != 0);
3847 QObject *childObject = rootObject->findChild<QObject*>("text");
3848 QVERIFY(childObject != 0);
3849 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3850 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3851 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3852 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3853 QVERIFY(!qobjectGuard.isNull());
3854 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3855 QCoreApplication::processEvents();
3856 QVERIFY(!qobjectGuard.isNull());
3857 QMetaObject::invokeMethod(object, "deassignCircular");
3858 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3859 QCoreApplication::processEvents();
3860 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3864 void tst_qdeclarativeecmascript::propertyVarReparent()
3866 // ensure that nothing breaks if we re-parent objects
3867 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3868 QObject *object = component.create();
3869 QVERIFY(object != 0);
3870 QMetaObject::invokeMethod(object, "assignVarProp");
3871 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3872 QCoreApplication::processEvents();
3873 QObject *rect = object->property("vp").value<QObject*>();
3874 QObject *text = rect->findChild<QObject*>("textOne");
3875 QObject *text2 = rect->findChild<QObject*>("textTwo");
3876 QWeakPointer<QObject> rectGuard(rect);
3877 QWeakPointer<QObject> textGuard(text);
3878 QWeakPointer<QObject> text2Guard(text2);
3879 QVERIFY(!rectGuard.isNull());
3880 QVERIFY(!textGuard.isNull());
3881 QVERIFY(!text2Guard.isNull());
3882 QCOMPARE(text->property("textCanary").toInt(), 11);
3883 QCOMPARE(text2->property("textCanary").toInt(), 12);
3884 // now construct an image which we will reparent.
3885 QMetaObject::invokeMethod(text2, "constructQObject");
3886 QObject *image = text2->property("vp").value<QObject*>();
3887 QWeakPointer<QObject> imageGuard(image);
3888 QVERIFY(!imageGuard.isNull());
3889 QCOMPARE(image->property("imageCanary").toInt(), 13);
3890 // now reparent the "Image" object (currently, it has JS ownership)
3891 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3892 QMetaObject::invokeMethod(text2, "deassignVp");
3893 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3894 QCoreApplication::processEvents();
3895 QCOMPARE(text->property("textCanary").toInt(), 11);
3896 QCOMPARE(text2->property("textCanary").toInt(), 22);
3897 QVERIFY(!imageGuard.isNull()); // should still be alive.
3898 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3899 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3900 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3901 QCoreApplication::processEvents();
3902 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3906 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3908 // sometimes reparenting can cause problems
3909 // (eg, if the ctxt is collected, varproperties are no longer available)
3910 // this test ensures that no crash occurs in that situation.
3911 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3912 QObject *object = component.create();
3913 QVERIFY(object != 0);
3914 QMetaObject::invokeMethod(object, "assignVarProp");
3915 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3916 QCoreApplication::processEvents();
3917 QObject *rect = object->property("vp").value<QObject*>();
3918 QObject *text = rect->findChild<QObject*>("textOne");
3919 QObject *text2 = rect->findChild<QObject*>("textTwo");
3920 QWeakPointer<QObject> rectGuard(rect);
3921 QWeakPointer<QObject> textGuard(text);
3922 QWeakPointer<QObject> text2Guard(text2);
3923 QVERIFY(!rectGuard.isNull());
3924 QVERIFY(!textGuard.isNull());
3925 QVERIFY(!text2Guard.isNull());
3926 QCOMPARE(text->property("textCanary").toInt(), 11);
3927 QCOMPARE(text2->property("textCanary").toInt(), 12);
3928 // now construct an image which we will reparent.
3929 QMetaObject::invokeMethod(text2, "constructQObject");
3930 QObject *image = text2->property("vp").value<QObject*>();
3931 QWeakPointer<QObject> imageGuard(image);
3932 QVERIFY(!imageGuard.isNull());
3933 QCOMPARE(image->property("imageCanary").toInt(), 13);
3934 // now reparent the "Image" object (currently, it has JS ownership)
3935 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3936 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3937 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3938 QCoreApplication::processEvents();
3939 QVERIFY(!imageGuard.isNull()); // should still be alive.
3940 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3942 QVERIFY(imageGuard.isNull()); // should now be dead.
3945 void tst_qdeclarativeecmascript::propertyVarCircular()
3947 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3948 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
3949 QObject *object = component.create();
3950 QVERIFY(object != 0);
3951 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3952 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3953 QCoreApplication::processEvents();
3954 QCOMPARE(object->property("canaryInt"), QVariant(5));
3955 QVariant canaryResourceVariant = object->property("canaryResource");
3956 QVERIFY(canaryResourceVariant.isValid());
3957 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3958 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3959 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3960 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3961 QCoreApplication::processEvents();
3962 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3963 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3964 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3965 QCoreApplication::processEvents();
3966 QCOMPARE(object->property("canaryInt"), QVariant(2));
3967 QCOMPARE(object->property("canaryResource"), QVariant(1));
3968 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3972 void tst_qdeclarativeecmascript::propertyVarCircular2()
3974 // track deletion of JS-owned parent item with Cpp-owned child
3975 // where the child has a var property referencing its parent.
3976 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
3977 QObject *object = component.create();
3978 QVERIFY(object != 0);
3979 QMetaObject::invokeMethod(object, "assignCircular");
3980 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3981 QCoreApplication::processEvents();
3982 QObject *rootObject = object->property("vp").value<QObject*>();
3983 QVERIFY(rootObject != 0);
3984 QObject *childObject = rootObject->findChild<QObject*>("text");
3985 QVERIFY(childObject != 0);
3986 QWeakPointer<QObject> rootObjectTracker(rootObject);
3987 QVERIFY(!rootObjectTracker.isNull());
3988 QWeakPointer<QObject> childObjectTracker(childObject);
3989 QVERIFY(!childObjectTracker.isNull());
3991 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3992 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3993 QMetaObject::invokeMethod(object, "deassignCircular");
3994 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3995 QCoreApplication::processEvents();
3996 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3997 QVERIFY(childObjectTracker.isNull()); // should have been collected
4001 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
4003 *(int*)(parameter) += 1;
4004 qPersistentDispose(object);
4007 void tst_qdeclarativeecmascript::propertyVarInheritance()
4009 int propertyVarWeakRefCallbackCount = 0;
4011 // enforce behaviour regarding element inheritance - ensure handle disposal.
4012 // The particular component under test here has a chain of references.
4013 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
4014 QObject *object = component.create();
4015 QVERIFY(object != 0);
4016 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
4017 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4018 QCoreApplication::processEvents();
4019 // we want to be able to track when the varProperties array of the last metaobject is disposed
4020 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
4021 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*>();
4022 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
4023 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
4024 v8::Persistent<v8::Value> icoCanaryHandle;
4025 v8::Persistent<v8::Value> ccoCanaryHandle;
4028 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4029 // public function which can return us a handle to something in the varProperties array.
4030 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4031 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4032 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4033 // as the varproperties array of each vmemo still references the resource.
4034 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4035 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4037 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4039 // now we deassign the var prop, which should trigger collection of item subtrees.
4040 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4041 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4042 QCoreApplication::processEvents();
4043 // ensure that there are only weak handles to the underlying varProperties array remaining.
4045 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4047 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4048 // to what remains are weak, all varProperties arrays must have been collected.
4051 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4053 int propertyVarWeakRefCallbackCount = 0;
4055 // The particular component under test here does NOT have a chain of references; the
4056 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4057 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4058 QObject *object = component.create();
4059 QVERIFY(object != 0);
4060 QMetaObject::invokeMethod(object, "assignCircular");
4061 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4062 QCoreApplication::processEvents();
4063 QObject *rootObject = object->property("vp").value<QObject*>();
4064 QVERIFY(rootObject != 0);
4065 QObject *childObject = rootObject->findChild<QObject*>("text");
4066 QVERIFY(childObject != 0);
4067 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4068 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4069 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4072 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4073 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
4074 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4076 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4077 QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
4078 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4080 QMetaObject::invokeMethod(object, "deassignCircular");
4081 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4082 QCoreApplication::processEvents();
4083 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4087 // Ensure that QObject type conversion works on binding assignment
4088 void tst_qdeclarativeecmascript::elementAssign()
4090 QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
4092 QObject *object = component.create();
4093 QVERIFY(object != 0);
4095 QCOMPARE(object->property("test").toBool(), true);
4101 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4103 QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
4105 QObject *object = component.create();
4106 QVERIFY(object != 0);
4108 QCOMPARE(object->property("test").toBool(), true);
4114 void tst_qdeclarativeecmascript::objectConversion()
4116 QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
4118 QObject *object = component.create();
4119 QVERIFY(object != 0);
4121 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4122 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4129 void tst_qdeclarativeecmascript::booleanConversion()
4131 QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
4133 QObject *object = component.create();
4134 QVERIFY(object != 0);
4136 QCOMPARE(object->property("test_true1").toBool(), true);
4137 QCOMPARE(object->property("test_true2").toBool(), true);
4138 QCOMPARE(object->property("test_true3").toBool(), true);
4139 QCOMPARE(object->property("test_true4").toBool(), true);
4140 QCOMPARE(object->property("test_true5").toBool(), true);
4142 QCOMPARE(object->property("test_false1").toBool(), false);
4143 QCOMPARE(object->property("test_false2").toBool(), false);
4144 QCOMPARE(object->property("test_false3").toBool(), false);
4149 void tst_qdeclarativeecmascript::handleReferenceManagement()
4154 // Linear QObject reference
4155 QDeclarativeEngine hrmEngine;
4156 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
4157 QObject *object = component.create();
4158 QVERIFY(object != 0);
4159 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4160 cro->setEngine(&hrmEngine);
4161 cro->setDtorCount(&dtorCount);
4162 QMetaObject::invokeMethod(object, "createReference");
4164 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4166 hrmEngine.collectGarbage();
4167 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4168 QCoreApplication::processEvents();
4169 QCOMPARE(dtorCount, 3);
4174 // Circular QObject reference
4175 QDeclarativeEngine hrmEngine;
4176 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
4177 QObject *object = component.create();
4178 QVERIFY(object != 0);
4179 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4180 cro->setEngine(&hrmEngine);
4181 cro->setDtorCount(&dtorCount);
4182 QMetaObject::invokeMethod(object, "circularReference");
4184 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4186 hrmEngine.collectGarbage();
4187 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4188 QCoreApplication::processEvents();
4189 QCOMPARE(dtorCount, 3);
4194 // Linear handle reference
4195 QDeclarativeEngine hrmEngine;
4196 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
4197 QObject *object = component.create();
4198 QVERIFY(object != 0);
4199 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4201 crh->setEngine(&hrmEngine);
4202 crh->setDtorCount(&dtorCount);
4203 QMetaObject::invokeMethod(object, "createReference");
4204 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4205 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4206 QVERIFY(first != 0);
4207 QVERIFY(second != 0);
4208 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4209 // now we have to reparent second and make second owned by JS.
4210 second->setParent(0);
4211 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4213 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4215 hrmEngine.collectGarbage();
4216 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4217 QCoreApplication::processEvents();
4218 QCOMPARE(dtorCount, 3);
4223 // Circular handle reference
4224 QDeclarativeEngine hrmEngine;
4225 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
4226 QObject *object = component.create();
4227 QVERIFY(object != 0);
4228 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4230 crh->setEngine(&hrmEngine);
4231 crh->setDtorCount(&dtorCount);
4232 QMetaObject::invokeMethod(object, "circularReference");
4233 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4234 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4235 QVERIFY(first != 0);
4236 QVERIFY(second != 0);
4237 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4238 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4239 // now we have to reparent and change ownership.
4240 first->setParent(0);
4241 second->setParent(0);
4242 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4243 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4245 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4247 hrmEngine.collectGarbage();
4248 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4249 QCoreApplication::processEvents();
4250 QCOMPARE(dtorCount, 3);
4255 // multiple engine interaction - linear reference
4256 QDeclarativeEngine hrmEngine1;
4257 QDeclarativeEngine hrmEngine2;
4258 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4259 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4260 QObject *object1 = component1.create();
4261 QObject *object2 = component2.create();
4262 QVERIFY(object1 != 0);
4263 QVERIFY(object2 != 0);
4264 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4265 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4268 crh1->setEngine(&hrmEngine1);
4269 crh2->setEngine(&hrmEngine2);
4270 crh1->setDtorCount(&dtorCount);
4271 crh2->setDtorCount(&dtorCount);
4272 QMetaObject::invokeMethod(object1, "createReference");
4273 QMetaObject::invokeMethod(object2, "createReference");
4274 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4275 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4276 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4277 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4278 QVERIFY(first1 != 0);
4279 QVERIFY(second1 != 0);
4280 QVERIFY(first2 != 0);
4281 QVERIFY(second2 != 0);
4282 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4283 // now we have to reparent second2 and make second2 owned by JS.
4284 second2->setParent(0);
4285 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4287 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4288 QCoreApplication::processEvents();
4289 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4292 hrmEngine1.collectGarbage();
4293 hrmEngine2.collectGarbage();
4294 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4295 QCoreApplication::processEvents();
4296 QCOMPARE(dtorCount, 6);
4301 // multiple engine interaction - circular reference
4302 QDeclarativeEngine hrmEngine1;
4303 QDeclarativeEngine hrmEngine2;
4304 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4305 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4306 QObject *object1 = component1.create();
4307 QObject *object2 = component2.create();
4308 QVERIFY(object1 != 0);
4309 QVERIFY(object2 != 0);
4310 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4311 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4314 crh1->setEngine(&hrmEngine1);
4315 crh2->setEngine(&hrmEngine2);
4316 crh1->setDtorCount(&dtorCount);
4317 crh2->setDtorCount(&dtorCount);
4318 QMetaObject::invokeMethod(object1, "createReference");
4319 QMetaObject::invokeMethod(object2, "createReference");
4320 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4321 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4322 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4323 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4324 QVERIFY(first1 != 0);
4325 QVERIFY(second1 != 0);
4326 QVERIFY(first2 != 0);
4327 QVERIFY(second2 != 0);
4328 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4329 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4330 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4331 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4332 // now we have to reparent and change ownership to JS.
4333 first1->setParent(0);
4334 second1->setParent(0);
4335 first2->setParent(0);
4336 second2->setParent(0);
4337 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4338 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4339 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4340 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4342 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4343 QCoreApplication::processEvents();
4344 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4347 hrmEngine1.collectGarbage();
4348 hrmEngine2.collectGarbage();
4349 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4350 QCoreApplication::processEvents();
4351 QCOMPARE(dtorCount, 6);
4356 // multiple engine interaction - linear reference with engine deletion
4357 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4358 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4359 QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4360 QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4361 QObject *object1 = component1.create();
4362 QObject *object2 = component2.create();
4363 QVERIFY(object1 != 0);
4364 QVERIFY(object2 != 0);
4365 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4366 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4369 crh1->setEngine(hrmEngine1);
4370 crh2->setEngine(hrmEngine2);
4371 crh1->setDtorCount(&dtorCount);
4372 crh2->setDtorCount(&dtorCount);
4373 QMetaObject::invokeMethod(object1, "createReference");
4374 QMetaObject::invokeMethod(object2, "createReference");
4375 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4376 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4377 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4378 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4379 QVERIFY(first1 != 0);
4380 QVERIFY(second1 != 0);
4381 QVERIFY(first2 != 0);
4382 QVERIFY(second2 != 0);
4383 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4384 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4385 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4386 // now we have to reparent and change ownership to JS.
4387 first1->setParent(crh1);
4388 second1->setParent(0);
4389 first2->setParent(0);
4390 second2->setParent(0);
4391 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4392 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4393 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4395 QCOMPARE(dtorCount, 0);
4398 QCOMPARE(dtorCount, 0);
4401 hrmEngine1->collectGarbage();
4402 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4403 QCoreApplication::processEvents();
4404 QCOMPARE(dtorCount, 6);
4409 void tst_qdeclarativeecmascript::stringArg()
4411 QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
4412 QObject *object = component.create();
4413 QVERIFY(object != 0);
4414 QMetaObject::invokeMethod(object, "success");
4415 QVERIFY(object->property("returnValue").toBool());
4417 QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4418 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4419 QMetaObject::invokeMethod(object, "failure");
4420 QVERIFY(object->property("returnValue").toBool());
4425 void tst_qdeclarativeecmascript::readonlyDeclaration()
4427 QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
4429 QObject *object = component.create();
4430 QVERIFY(object != 0);
4432 QCOMPARE(object->property("test").toBool(), true);
4437 Q_DECLARE_METATYPE(QList<int>)
4438 Q_DECLARE_METATYPE(QList<qreal>)
4439 Q_DECLARE_METATYPE(QList<bool>)
4440 Q_DECLARE_METATYPE(QList<QString>)
4441 Q_DECLARE_METATYPE(QList<QUrl>)
4442 void tst_qdeclarativeecmascript::sequenceConversionRead()
4445 QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
4446 QDeclarativeComponent component(&engine, qmlFile);
4447 QObject *object = component.create();
4448 QVERIFY(object != 0);
4449 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4452 QMetaObject::invokeMethod(object, "readSequences");
4453 QList<int> intList; intList << 1 << 2 << 3 << 4;
4454 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4455 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4456 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4457 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4458 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4459 QList<bool> boolList; boolList << true << false << true << false;
4460 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4461 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4462 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4463 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4464 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4465 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4466 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4467 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4468 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4469 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4470 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4472 QMetaObject::invokeMethod(object, "readSequenceElements");
4473 QCOMPARE(object->property("intVal").toInt(), 2);
4474 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4475 QCOMPARE(object->property("boolVal").toBool(), false);
4476 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4477 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4478 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4480 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4481 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4483 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4484 QDeclarativeProperty seqProp(seq, "intListProperty");
4485 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4486 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4487 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4489 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4490 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4496 QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
4497 QDeclarativeComponent component(&engine, qmlFile);
4498 QObject *object = component.create();
4499 QVERIFY(object != 0);
4500 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4503 // we haven't registered QList<QPoint> as a sequence type.
4504 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4505 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4506 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4507 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4509 QMetaObject::invokeMethod(object, "performTest");
4511 // QList<QPoint> has not been registered as a sequence type.
4512 QCOMPARE(object->property("pointListLength").toInt(), 0);
4513 QVERIFY(!object->property("pointList").isValid());
4514 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4515 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4516 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4522 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4525 QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
4526 QDeclarativeComponent component(&engine, qmlFile);
4527 QObject *object = component.create();
4528 QVERIFY(object != 0);
4529 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4532 QMetaObject::invokeMethod(object, "writeSequences");
4533 QCOMPARE(object->property("success").toBool(), true);
4535 QMetaObject::invokeMethod(object, "writeSequenceElements");
4536 QCOMPARE(object->property("success").toBool(), true);
4538 QMetaObject::invokeMethod(object, "writeOtherElements");
4539 QCOMPARE(object->property("success").toBool(), true);
4541 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4542 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4548 QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
4549 QDeclarativeComponent component(&engine, qmlFile);
4550 QObject *object = component.create();
4551 QVERIFY(object != 0);
4552 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4555 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4556 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4557 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4559 QMetaObject::invokeMethod(object, "performTest");
4561 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4562 QCOMPARE(seq->pointListProperty(), pointList);
4568 void tst_qdeclarativeecmascript::sequenceConversionArray()
4570 // ensure that in JS the returned sequences act just like normal JS Arrays.
4571 QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
4572 QDeclarativeComponent component(&engine, qmlFile);
4573 QObject *object = component.create();
4574 QVERIFY(object != 0);
4575 QMetaObject::invokeMethod(object, "indexedAccess");
4576 QVERIFY(object->property("success").toBool());
4577 QMetaObject::invokeMethod(object, "arrayOperations");
4578 QVERIFY(object->property("success").toBool());
4579 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4580 QVERIFY(object->property("success").toBool());
4581 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4582 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4586 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4588 // ensure that sequence conversion operations work correctly in a worker thread
4589 // and that serialisation between the main and worker thread succeeds.
4590 QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
4591 QDeclarativeComponent component(&engine, qmlFile);
4592 QObject *object = component.create();
4593 QVERIFY(object != 0);
4595 QMetaObject::invokeMethod(object, "testIntSequence");
4596 QTRY_VERIFY(object->property("finished").toBool());
4597 QVERIFY(object->property("success").toBool());
4599 QMetaObject::invokeMethod(object, "testQrealSequence");
4600 QTRY_VERIFY(object->property("finished").toBool());
4601 QVERIFY(object->property("success").toBool());
4603 QMetaObject::invokeMethod(object, "testBoolSequence");
4604 QTRY_VERIFY(object->property("finished").toBool());
4605 QVERIFY(object->property("success").toBool());
4607 QMetaObject::invokeMethod(object, "testStringSequence");
4608 QTRY_VERIFY(object->property("finished").toBool());
4609 QVERIFY(object->property("success").toBool());
4611 QMetaObject::invokeMethod(object, "testQStringSequence");
4612 QTRY_VERIFY(object->property("finished").toBool());
4613 QVERIFY(object->property("success").toBool());
4615 QMetaObject::invokeMethod(object, "testUrlSequence");
4616 QTRY_VERIFY(object->property("finished").toBool());
4617 QVERIFY(object->property("success").toBool());
4619 QMetaObject::invokeMethod(object, "testVariantSequence");
4620 QTRY_VERIFY(object->property("finished").toBool());
4621 QVERIFY(object->property("success").toBool());
4626 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4629 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
4630 QDeclarativeComponent component(&engine, qmlFile);
4631 QObject *object = component.create();
4632 QVERIFY(object != 0);
4633 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4634 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4635 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4636 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4637 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4642 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
4643 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4644 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4645 QDeclarativeComponent component(&engine, qmlFile);
4646 QObject *object = component.create();
4647 QVERIFY(object != 0);
4652 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4654 QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
4655 QDeclarativeComponent component(&engine, qmlFile);
4656 QObject *object = component.create();
4657 QVERIFY(object != 0);
4658 QMetaObject::invokeMethod(object, "testCopySequences");
4659 QCOMPARE(object->property("success").toBool(), true);
4660 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4661 QCOMPARE(object->property("success").toBool(), true);
4662 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4663 QCOMPARE(object->property("success").toBool(), true);
4667 void tst_qdeclarativeecmascript::assignSequenceTypes()
4669 // test binding array to sequence type property
4671 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
4672 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4673 QVERIFY(object != 0);
4674 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4675 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4676 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4677 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4678 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4679 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4683 // test binding literal to sequence type property
4685 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
4686 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4687 QVERIFY(object != 0);
4688 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4689 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4690 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4691 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4692 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4693 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4697 // test binding single value to sequence type property
4699 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
4700 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4701 QVERIFY(object != 0);
4702 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4703 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4704 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4705 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4709 // test assigning array to sequence type property in js function
4711 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
4712 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4713 QVERIFY(object != 0);
4714 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4715 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4716 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4717 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4718 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4719 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4723 // test assigning literal to sequence type property in js function
4725 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
4726 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4727 QVERIFY(object != 0);
4728 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4729 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4730 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4731 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4732 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4733 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4737 // test assigning single value to sequence type property in js function
4739 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
4740 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4741 QVERIFY(object != 0);
4742 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4743 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4744 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4745 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4749 // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
4751 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
4752 QObject *object = component.create();
4753 QVERIFY(object != 0);
4754 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
4755 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
4756 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
4757 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
4758 MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
4759 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
4760 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4761 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4762 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4763 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4764 QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4769 // Test that assigning a null object works
4770 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4771 void tst_qdeclarativeecmascript::nullObjectBinding()
4773 QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
4775 QObject *object = component.create();
4776 QVERIFY(object != 0);
4778 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4783 // Test that bindings don't evaluate once the engine has been destroyed
4784 void tst_qdeclarativeecmascript::deletedEngine()
4786 QDeclarativeEngine *engine = new QDeclarativeEngine;
4787 QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
4789 QObject *object = component.create();
4790 QVERIFY(object != 0);
4792 QCOMPARE(object->property("a").toInt(), 39);
4793 object->setProperty("b", QVariant(9));
4794 QCOMPARE(object->property("a").toInt(), 117);
4798 QCOMPARE(object->property("a").toInt(), 117);
4799 object->setProperty("b", QVariant(10));
4800 QCOMPARE(object->property("a").toInt(), 117);
4805 // Test the crashing part of QTBUG-9705
4806 void tst_qdeclarativeecmascript::libraryScriptAssert()
4808 QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
4810 QObject *object = component.create();
4811 QVERIFY(object != 0);
4816 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4818 QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
4820 QObject *object = component.create();
4821 QVERIFY(object != 0);
4823 QCOMPARE(object->property("test1").toInt(), 10);
4824 QCOMPARE(object->property("test2").toInt(), 11);
4826 object->setProperty("runTest", true);
4828 QCOMPARE(object->property("test1"), QVariant());
4829 QCOMPARE(object->property("test2"), QVariant());
4835 void tst_qdeclarativeecmascript::qtbug_9792()
4837 QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
4839 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4841 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4842 QVERIFY(object != 0);
4844 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4845 object->basicSignal();
4849 transientErrorsMsgCount = 0;
4850 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4852 object->basicSignal();
4854 qInstallMsgHandler(old);
4856 QCOMPARE(transientErrorsMsgCount, 0);
4861 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4862 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4864 QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
4866 QObject *o = component.create();
4869 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4870 QVERIFY(nested != 0);
4872 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4875 nested = qvariant_cast<QObject *>(o->property("object"));
4876 QVERIFY(nested == 0);
4878 // If the bug is present, the next line will crash
4882 // Test that we shut down without stupid warnings
4883 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4886 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
4888 QObject *o = component.create();
4890 transientErrorsMsgCount = 0;
4891 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4895 qInstallMsgHandler(old);
4897 QCOMPARE(transientErrorsMsgCount, 0);
4902 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
4904 QObject *o = component.create();
4906 transientErrorsMsgCount = 0;
4907 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4911 qInstallMsgHandler(old);
4913 QCOMPARE(transientErrorsMsgCount, 0);
4917 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4920 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
4922 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4925 QVERIFY(o->objectProperty() != 0);
4927 o->setProperty("runTest", true);
4929 QVERIFY(o->objectProperty() == 0);
4935 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
4937 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4940 QVERIFY(o->objectProperty() == 0);
4946 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4948 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
4950 QString url = component.url().toString();
4951 QString warning = url + ":4: Unable to assign a function to a property.";
4952 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4954 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4957 QVERIFY(!o->property("a").isValid());
4962 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4964 QFETCH(QString, triggerProperty);
4966 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4967 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4969 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4971 QVERIFY(!o->property("a").isValid());
4973 o->setProperty("aNumber", QVariant(5));
4974 o->setProperty(triggerProperty.toUtf8().constData(), true);
4975 QCOMPARE(o->property("a"), QVariant(50));
4977 o->setProperty("aNumber", QVariant(10));
4978 QCOMPARE(o->property("a"), QVariant(100));
4983 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4985 QTest::addColumn<QString>("triggerProperty");
4987 QTest::newRow("assign to property") << "assignToProperty";
4988 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4990 QTest::newRow("assign to value type") << "assignToValueType";
4992 QTest::newRow("use 'this'") << "assignWithThis";
4993 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4996 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4998 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4999 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
5001 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5003 QVERIFY(!o->property("a").isValid());
5005 o->setProperty("assignFuncWithoutReturn", true);
5006 QVERIFY(!o->property("a").isValid());
5008 QString url = component.url().toString();
5009 QString warning = url + ":67: Unable to assign QString to int";
5010 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5011 o->setProperty("assignWrongType", true);
5013 warning = url + ":71: Unable to assign QString to int";
5014 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5015 o->setProperty("assignWrongTypeToValueType", true);
5020 void tst_qdeclarativeecmascript::eval()
5022 QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
5024 QObject *o = component.create();
5027 QCOMPARE(o->property("test1").toBool(), true);
5028 QCOMPARE(o->property("test2").toBool(), true);
5029 QCOMPARE(o->property("test3").toBool(), true);
5030 QCOMPARE(o->property("test4").toBool(), true);
5031 QCOMPARE(o->property("test5").toBool(), true);
5036 void tst_qdeclarativeecmascript::function()
5038 QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
5040 QObject *o = component.create();
5043 QCOMPARE(o->property("test1").toBool(), true);
5044 QCOMPARE(o->property("test2").toBool(), true);
5045 QCOMPARE(o->property("test3").toBool(), true);
5050 // Test the "Qt.include" method
5051 void tst_qdeclarativeecmascript::include()
5053 // Non-library relative include
5055 QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
5056 QObject *o = component.create();
5059 QCOMPARE(o->property("test0").toInt(), 99);
5060 QCOMPARE(o->property("test1").toBool(), true);
5061 QCOMPARE(o->property("test2").toBool(), true);
5062 QCOMPARE(o->property("test2_1").toBool(), true);
5063 QCOMPARE(o->property("test3").toBool(), true);
5064 QCOMPARE(o->property("test3_1").toBool(), true);
5069 // Library relative include
5071 QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
5072 QObject *o = component.create();
5075 QCOMPARE(o->property("test0").toInt(), 99);
5076 QCOMPARE(o->property("test1").toBool(), true);
5077 QCOMPARE(o->property("test2").toBool(), true);
5078 QCOMPARE(o->property("test2_1").toBool(), true);
5079 QCOMPARE(o->property("test3").toBool(), true);
5080 QCOMPARE(o->property("test3_1").toBool(), true);
5087 QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
5088 QObject *o = component.create();
5091 QCOMPARE(o->property("test1").toBool(), true);
5092 QCOMPARE(o->property("test2").toBool(), true);
5093 QCOMPARE(o->property("test3").toBool(), true);
5094 QCOMPARE(o->property("test4").toBool(), true);
5095 QCOMPARE(o->property("test5").toBool(), true);
5096 QCOMPARE(o->property("test6").toBool(), true);
5101 // Including file with ".pragma library"
5103 QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
5104 QObject *o = component.create();
5106 QCOMPARE(o->property("test1").toInt(), 100);
5113 TestHTTPServer server(8111);
5114 QVERIFY(server.isValid());
5115 server.serveDirectory(dataDirectory());
5117 QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
5118 QObject *o = component.create();
5121 QTRY_VERIFY(o->property("done").toBool() == true);
5122 QTRY_VERIFY(o->property("done2").toBool() == true);
5124 QCOMPARE(o->property("test1").toBool(), true);
5125 QCOMPARE(o->property("test2").toBool(), true);
5126 QCOMPARE(o->property("test3").toBool(), true);
5127 QCOMPARE(o->property("test4").toBool(), true);
5128 QCOMPARE(o->property("test5").toBool(), true);
5130 QCOMPARE(o->property("test6").toBool(), true);
5131 QCOMPARE(o->property("test7").toBool(), true);
5132 QCOMPARE(o->property("test8").toBool(), true);
5133 QCOMPARE(o->property("test9").toBool(), true);
5134 QCOMPARE(o->property("test10").toBool(), true);
5141 TestHTTPServer server(8111);
5142 QVERIFY(server.isValid());
5143 server.serveDirectory(dataDirectory());
5145 QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
5146 QObject *o = component.create();
5149 QTRY_VERIFY(o->property("done").toBool() == true);
5151 QCOMPARE(o->property("test1").toBool(), true);
5152 QCOMPARE(o->property("test2").toBool(), true);
5153 QCOMPARE(o->property("test3").toBool(), true);
5159 void tst_qdeclarativeecmascript::signalHandlers()
5161 QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
5162 QObject *o = component.create();
5165 QVERIFY(o->property("count").toInt() == 0);
5166 QMetaObject::invokeMethod(o, "testSignalCall");
5167 QCOMPARE(o->property("count").toInt(), 1);
5169 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5170 QCOMPARE(o->property("count").toInt(), 1);
5171 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5173 QVERIFY(o->property("funcCount").toInt() == 0);
5174 QMetaObject::invokeMethod(o, "testSignalConnection");
5175 QCOMPARE(o->property("funcCount").toInt(), 1);
5177 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5178 QCOMPARE(o->property("funcCount").toInt(), 2);
5180 QMetaObject::invokeMethod(o, "testSignalDefined");
5181 QCOMPARE(o->property("definedResult").toBool(), true);
5183 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5184 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5189 void tst_qdeclarativeecmascript::qtbug_10696()
5191 QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
5192 QObject *o = component.create();
5197 void tst_qdeclarativeecmascript::qtbug_11606()
5199 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
5200 QObject *o = component.create();
5202 QCOMPARE(o->property("test").toBool(), true);
5206 void tst_qdeclarativeecmascript::qtbug_11600()
5208 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
5209 QObject *o = component.create();
5211 QCOMPARE(o->property("test").toBool(), true);
5215 void tst_qdeclarativeecmascript::qtbug_21864()
5217 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
5218 QObject *o = component.create();
5220 QCOMPARE(o->property("test").toBool(), true);
5224 void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
5227 QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
5228 QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
5229 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5230 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5231 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5232 QObject *o = component.create();
5234 QCOMPARE(o->property("test").toBool(), true);
5238 // Reading and writing non-scriptable properties should fail
5239 void tst_qdeclarativeecmascript::nonscriptable()
5241 QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
5242 QObject *o = component.create();
5244 QCOMPARE(o->property("readOk").toBool(), true);
5245 QCOMPARE(o->property("writeOk").toBool(), true);
5249 // deleteLater() should not be callable from QML
5250 void tst_qdeclarativeecmascript::deleteLater()
5252 QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
5253 QObject *o = component.create();
5255 QCOMPARE(o->property("test").toBool(), true);
5259 void tst_qdeclarativeecmascript::in()
5261 QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
5262 QObject *o = component.create();
5264 QCOMPARE(o->property("test1").toBool(), true);
5265 QCOMPARE(o->property("test2").toBool(), true);
5269 void tst_qdeclarativeecmascript::typeOf()
5271 QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
5273 // These warnings should not happen once QTBUG-21864 is fixed
5274 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5275 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5277 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5278 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5280 QObject *o = component.create();
5283 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5284 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5285 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5286 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5287 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5288 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5289 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5290 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5291 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5292 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5297 void tst_qdeclarativeecmascript::sharedAttachedObject()
5299 QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
5300 QObject *o = component.create();
5302 QCOMPARE(o->property("test1").toBool(), true);
5303 QCOMPARE(o->property("test2").toBool(), true);
5308 void tst_qdeclarativeecmascript::objectName()
5310 QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
5311 QObject *o = component.create();
5314 QCOMPARE(o->property("test1").toString(), QString("hello"));
5315 QCOMPARE(o->property("test2").toString(), QString("ell"));
5317 o->setObjectName("world");
5319 QCOMPARE(o->property("test1").toString(), QString("world"));
5320 QCOMPARE(o->property("test2").toString(), QString("orl"));
5325 void tst_qdeclarativeecmascript::writeRemovesBinding()
5327 QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
5328 QObject *o = component.create();
5331 QCOMPARE(o->property("test").toBool(), true);
5336 // Test bindings assigned to alias properties actually assign to the alias' target
5337 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5339 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
5340 QObject *o = component.create();
5343 QCOMPARE(o->property("test").toBool(), true);
5348 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5349 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5352 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
5353 QObject *o = component.create();
5356 QCOMPARE(o->property("test").toBool(), true);
5362 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
5363 QObject *o = component.create();
5366 QCOMPARE(o->property("test").toBool(), true);
5372 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
5373 QObject *o = component.create();
5376 QCOMPARE(o->property("test").toBool(), true);
5382 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5383 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5386 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
5387 QObject *o = component.create();
5390 QCOMPARE(o->property("test").toBool(), true);
5396 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
5397 QObject *o = component.create();
5400 QCOMPARE(o->property("test").toBool(), true);
5406 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
5407 QObject *o = component.create();
5410 QCOMPARE(o->property("test").toBool(), true);
5416 // Allow an alais to a composite element
5418 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5420 QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
5422 QObject *object = component.create();
5423 QVERIFY(object != 0);
5428 void tst_qdeclarativeecmascript::qtbug_20344()
5430 QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
5432 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5433 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5435 QObject *object = component.create();
5436 QVERIFY(object != 0);
5441 void tst_qdeclarativeecmascript::revisionErrors()
5444 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
5445 QString url = component.url().toString();
5447 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5448 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5449 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5451 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5452 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5453 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5454 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5455 QVERIFY(object != 0);
5459 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
5460 QString url = component.url().toString();
5462 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5463 // method2, prop2 from MyRevisionedClass not available
5464 // method4, prop4 from MyRevisionedSubclass not available
5465 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5466 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5467 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5468 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5469 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5471 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5472 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5473 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5474 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5475 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5476 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5477 QVERIFY(object != 0);
5481 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
5482 QString url = component.url().toString();
5484 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5485 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5486 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5487 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5488 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5489 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5490 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5491 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5492 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5493 QVERIFY(object != 0);
5498 void tst_qdeclarativeecmascript::revision()
5501 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
5502 QString url = component.url().toString();
5504 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5505 QVERIFY(object != 0);
5509 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
5510 QString url = component.url().toString();
5512 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5513 QVERIFY(object != 0);
5517 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
5518 QString url = component.url().toString();
5520 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5521 QVERIFY(object != 0);
5524 // Test that non-root classes can resolve revisioned methods
5526 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
5528 QObject *object = component.create();
5529 QVERIFY(object != 0);
5530 QCOMPARE(object->property("test").toReal(), 11.);
5535 void tst_qdeclarativeecmascript::realToInt()
5537 QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
5538 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5539 QVERIFY(object != 0);
5541 QMetaObject::invokeMethod(object, "test1");
5542 QCOMPARE(object->value(), int(4));
5543 QMetaObject::invokeMethod(object, "test2");
5544 QCOMPARE(object->value(), int(8));
5547 void tst_qdeclarativeecmascript::urlProperty()
5550 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
5551 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5552 QVERIFY(object != 0);
5553 object->setStringProperty("http://qt-project.org");
5554 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5555 QCOMPARE(object->intProperty(), 123);
5556 QCOMPARE(object->value(), 1);
5557 QCOMPARE(object->property("result").toBool(), true);
5561 void tst_qdeclarativeecmascript::urlPropertyWithEncoding()
5564 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.2.qml"));
5565 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5566 QVERIFY(object != 0);
5567 object->setStringProperty("http://qt-project.org");
5569 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5570 QCOMPARE(object->urlProperty(), encoded);
5571 QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
5572 QCOMPARE(object->property("result").toBool(), true);
5576 void tst_qdeclarativeecmascript::urlListPropertyWithEncoding()
5579 QDeclarativeComponent component(&engine, testFileUrl("urlListProperty.qml"));
5580 QObject *object = component.create();
5581 QVERIFY(object != 0);
5582 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
5583 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
5584 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
5585 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
5586 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
5588 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5589 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
5590 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
5591 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5592 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5597 void tst_qdeclarativeecmascript::dynamicString()
5599 QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
5600 QObject *object = component.create();
5601 QVERIFY(object != 0);
5602 QCOMPARE(object->property("stringProperty").toString(),
5603 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5606 void tst_qdeclarativeecmascript::automaticSemicolon()
5608 QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
5609 QObject *object = component.create();
5610 QVERIFY(object != 0);
5613 void tst_qdeclarativeecmascript::unaryExpression()
5615 QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
5616 QObject *object = component.create();
5617 QVERIFY(object != 0);
5620 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5621 void tst_qdeclarativeecmascript::doubleEvaluate()
5623 QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
5624 QObject *object = component.create();
5625 QVERIFY(object != 0);
5626 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5628 QCOMPARE(wc->count(), 1);
5630 wc->setProperty("x", 9);
5632 QCOMPARE(wc->count(), 2);
5637 static QStringList messages;
5638 static void captureMsgHandler(QtMsgType, const char *msg)
5640 messages.append(QLatin1String(msg));
5643 void tst_qdeclarativeecmascript::nonNotifyable()
5645 QV4Compiler::enableV4(false);
5646 QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
5647 QV4Compiler::enableV4(true);
5649 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5651 QObject *object = component.create();
5652 qInstallMsgHandler(old);
5654 QVERIFY(object != 0);
5656 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5657 component.url().toString() +
5658 QLatin1String(":5 depends on non-NOTIFYable properties:");
5659 QString expected2 = QLatin1String(" ") +
5660 QLatin1String(object->metaObject()->className()) +
5661 QLatin1String("::value");
5663 QCOMPARE(messages.length(), 2);
5664 QCOMPARE(messages.at(0), expected1);
5665 QCOMPARE(messages.at(1), expected2);
5670 void tst_qdeclarativeecmascript::forInLoop()
5672 QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
5673 QObject *object = component.create();
5674 QVERIFY(object != 0);
5676 QMetaObject::invokeMethod(object, "listProperty");
5678 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5679 QCOMPARE(r.size(), 3);
5680 QCOMPARE(r[0],QLatin1String("0=obj1"));
5681 QCOMPARE(r[1],QLatin1String("1=obj2"));
5682 QCOMPARE(r[2],QLatin1String("2=obj3"));
5684 //TODO: should test for in loop for other objects (such as QObjects) as well.
5689 // An object the binding depends on is deleted while the binding is still running
5690 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5692 QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
5693 QObject *object = component.create();
5694 QVERIFY(object != 0);
5698 void tst_qdeclarativeecmascript::qtbug_22679()
5701 object.setStringProperty(QLatin1String("Please work correctly"));
5702 engine.rootContext()->setContextProperty("contextProp", &object);
5704 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
5705 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5706 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5708 QObject *o = component.create();
5710 QCOMPARE(warningsSpy.count(), 0);
5714 void tst_qdeclarativeecmascript::qtbug_22843_data()
5716 QTest::addColumn<bool>("library");
5718 QTest::newRow("without .pragma library") << false;
5719 QTest::newRow("with .pragma library") << true;
5722 void tst_qdeclarativeecmascript::qtbug_22843()
5724 QFETCH(bool, library);
5726 QString fileName("qtbug_22843");
5728 fileName += QLatin1String(".library");
5729 fileName += QLatin1String(".qml");
5731 QDeclarativeComponent component(&engine, testFileUrl(fileName));
5732 QString url = component.url().toString();
5733 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5734 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5736 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5737 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5738 for (int x = 0; x < 3; ++x) {
5739 warningsSpy.clear();
5740 // For libraries, only the first import attempt should produce a
5741 // SyntaxError warning; subsequent component creation should not
5742 // attempt to reload the script.
5743 bool expectSyntaxError = !library || (x == 0);
5744 if (expectSyntaxError)
5745 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5746 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5747 QObject *object = component.create();
5748 QVERIFY(object != 0);
5749 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5755 void tst_qdeclarativeecmascript::switchStatement()
5758 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
5759 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5760 QVERIFY(object != 0);
5762 // `object->value()' is the number of executed statements
5764 object->setStringProperty("A");
5765 QCOMPARE(object->value(), 5);
5767 object->setStringProperty("S");
5768 QCOMPARE(object->value(), 3);
5770 object->setStringProperty("D");
5771 QCOMPARE(object->value(), 3);
5773 object->setStringProperty("F");
5774 QCOMPARE(object->value(), 4);
5776 object->setStringProperty("something else");
5777 QCOMPARE(object->value(), 1);
5781 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
5782 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5783 QVERIFY(object != 0);
5785 // `object->value()' is the number of executed statements
5787 object->setStringProperty("A");
5788 QCOMPARE(object->value(), 5);
5790 object->setStringProperty("S");
5791 QCOMPARE(object->value(), 3);
5793 object->setStringProperty("D");
5794 QCOMPARE(object->value(), 3);
5796 object->setStringProperty("F");
5797 QCOMPARE(object->value(), 3);
5799 object->setStringProperty("something else");
5800 QCOMPARE(object->value(), 4);
5804 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
5805 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5806 QVERIFY(object != 0);
5808 // `object->value()' is the number of executed statements
5810 object->setStringProperty("A");
5811 QCOMPARE(object->value(), 5);
5813 object->setStringProperty("S");
5814 QCOMPARE(object->value(), 3);
5816 object->setStringProperty("D");
5817 QCOMPARE(object->value(), 3);
5819 object->setStringProperty("F");
5820 QCOMPARE(object->value(), 3);
5822 object->setStringProperty("something else");
5823 QCOMPARE(object->value(), 6);
5827 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
5829 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5830 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5832 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5833 QVERIFY(object != 0);
5835 // `object->value()' is the number of executed statements
5837 object->setStringProperty("A");
5838 QCOMPARE(object->value(), 5);
5840 object->setStringProperty("S");
5841 QCOMPARE(object->value(), 3);
5843 object->setStringProperty("D");
5844 QCOMPARE(object->value(), 3);
5846 object->setStringProperty("F");
5847 QCOMPARE(object->value(), 3);
5849 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5851 object->setStringProperty("something else");
5855 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
5856 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5857 QVERIFY(object != 0);
5859 // `object->value()' is the number of executed statements
5861 object->setStringProperty("A");
5862 QCOMPARE(object->value(), 1);
5864 object->setStringProperty("S");
5865 QCOMPARE(object->value(), 1);
5867 object->setStringProperty("D");
5868 QCOMPARE(object->value(), 1);
5870 object->setStringProperty("F");
5871 QCOMPARE(object->value(), 1);
5873 object->setStringProperty("something else");
5874 QCOMPARE(object->value(), 1);
5878 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
5879 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5880 QVERIFY(object != 0);
5882 // `object->value()' is the number of executed statements
5884 object->setStringProperty("A");
5885 QCOMPARE(object->value(), 123);
5887 object->setStringProperty("S");
5888 QCOMPARE(object->value(), 123);
5890 object->setStringProperty("D");
5891 QCOMPARE(object->value(), 321);
5893 object->setStringProperty("F");
5894 QCOMPARE(object->value(), 321);
5896 object->setStringProperty("something else");
5897 QCOMPARE(object->value(), 0);
5901 void tst_qdeclarativeecmascript::withStatement()
5904 QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
5905 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5906 QVERIFY(object != 0);
5908 QCOMPARE(object->value(), 123);
5912 void tst_qdeclarativeecmascript::tryStatement()
5915 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
5916 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5917 QVERIFY(object != 0);
5919 QCOMPARE(object->value(), 123);
5923 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
5924 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5925 QVERIFY(object != 0);
5927 QCOMPARE(object->value(), 321);
5931 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
5932 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5933 QVERIFY(object != 0);
5935 QCOMPARE(object->value(), 1);
5939 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
5940 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5941 QVERIFY(object != 0);
5943 QCOMPARE(object->value(), 1);
5947 QTEST_MAIN(tst_qdeclarativeecmascript)
5949 #include "tst_qdeclarativeecmascript.moc"