1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include <private/qv8gccallback_p.h>
53 #include <private/qdeclarativevmemetaobject_p.h>
54 #include "testtypes.h"
55 #include "testhttpserver.h"
56 #include "../shared/util.h"
59 This test covers evaluation of ECMAScript expressions and bindings from within
60 QML. This does not include static QML language issues.
62 Static QML language issues are covered in qmllanguage
64 inline QUrl TEST_FILE(const QString &filename)
66 return QUrl::fromLocalFile(TESTDATA(filename));
69 inline QUrl TEST_FILE(const char *filename)
71 return TEST_FILE(QLatin1String(filename));
74 class tst_qdeclarativeecmascript : public QObject
78 tst_qdeclarativeecmascript() {}
82 void assignBasicTypes();
83 void idShortcutInvalidates();
84 void boolPropertiesEvaluateAsBool();
86 void signalAssignment();
88 void basicExpressions();
89 void basicExpressions_data();
90 void arrayExpressions();
91 void contextPropertiesTriggerReeval();
92 void objectPropertiesTriggerReeval();
93 void deferredProperties();
94 void deferredPropertiesErrors();
95 void extensionObjects();
96 void overrideExtensionProperties();
97 void attachedProperties();
99 void valueTypeFunctions();
100 void constantsOverrideBindings();
101 void outerBindingOverridesInnerBinding();
102 void aliasPropertyAndBinding();
103 void aliasPropertyReset();
104 void nonExistentAttachedObject();
107 void signalParameterTypes();
108 void objectsCompareAsEqual();
109 void dynamicCreation_data();
110 void dynamicCreation();
111 void dynamicDestruction();
112 void objectToString();
113 void objectHasOwnProperty();
114 void selfDeletingBinding();
115 void extendedObjectPropertyLookup();
117 void functionErrors();
118 void propertyAssignmentErrors();
119 void signalTriggeredBindings();
120 void listProperties();
121 void exceptionClearsOnReeval();
122 void exceptionSlotProducesWarning();
123 void exceptionBindingProducesWarning();
124 void transientErrors();
125 void shutdownErrors();
126 void compositePropertyType();
128 void undefinedResetsProperty();
129 void listToVariant();
130 void listAssignment();
131 void multiEngineObject();
132 void deletedObject();
133 void attachedPropertyScope();
134 void scriptConnect();
135 void scriptDisconnect();
137 void cppOwnershipReturnValue();
138 void ownershipCustomReturnValue();
139 void qlistqobjectMethods();
140 void strictlyEquals();
142 void numberAssignment();
143 void propertySplicing();
144 void signalWithUnknownTypes();
145 void signalWithJSValueInVariant_data();
146 void signalWithJSValueInVariant();
147 void signalWithJSValueInVariant_twoEngines_data();
148 void signalWithJSValueInVariant_twoEngines();
149 void moduleApi_data();
151 void importScripts_data();
152 void importScripts();
153 void scarceResources();
154 void propertyChangeSlots();
155 void propertyVar_data();
157 void propertyVarCpp();
158 void propertyVarOwnership();
159 void propertyVarImplicitOwnership();
160 void propertyVarReparent();
161 void propertyVarReparentNullContext();
162 void propertyVarCircular();
163 void propertyVarCircular2();
164 void propertyVarInheritance();
165 void propertyVarInheritance2();
166 void elementAssign();
167 void objectPassThroughSignals();
168 void objectConversion();
169 void booleanConversion();
170 void handleReferenceManagement();
175 void dynamicCreationCrash();
176 void dynamicCreationOwnership();
178 void nullObjectBinding();
179 void deletedEngine();
180 void libraryScriptAssert();
181 void variantsAssignedUndefined();
183 void qtcreatorbug_1289();
184 void noSpuriousWarningsAtShutdown();
185 void canAssignNullToQObject();
186 void functionAssignment_fromBinding();
187 void functionAssignment_fromJS();
188 void functionAssignment_fromJS_data();
189 void functionAssignmentfromJS_invalid();
195 void nonscriptable();
199 void sharedAttachedObject();
201 void writeRemovesBinding();
202 void aliasBindingsAssignCorrectly();
203 void aliasBindingsOverrideTarget();
204 void aliasWritesOverrideBindings();
205 void aliasToCompositeElement();
207 void dynamicString();
209 void signalHandlers();
210 void doubleEvaluate();
213 void callQtInvokables();
214 void invokableObjectArg();
215 void invokableObjectRet();
217 void revisionErrors();
220 void automaticSemicolon();
223 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
224 QDeclarativeEngine engine;
227 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
229 void tst_qdeclarativeecmascript::assignBasicTypes()
232 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
233 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
234 QVERIFY(object != 0);
235 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
236 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
237 QCOMPARE(object->stringProperty(), QString("Hello World!"));
238 QCOMPARE(object->uintProperty(), uint(10));
239 QCOMPARE(object->intProperty(), -19);
240 QCOMPARE((float)object->realProperty(), float(23.2));
241 QCOMPARE((float)object->doubleProperty(), float(-19.75));
242 QCOMPARE((float)object->floatProperty(), float(8.5));
243 QCOMPARE(object->colorProperty(), QColor("red"));
244 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
245 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
246 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
247 QCOMPARE(object->pointProperty(), QPoint(99,13));
248 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
249 QCOMPARE(object->sizeProperty(), QSize(99, 13));
250 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
251 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
252 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
253 QCOMPARE(object->boolProperty(), true);
254 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
255 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
256 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
260 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
261 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
262 QVERIFY(object != 0);
263 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
264 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
265 QCOMPARE(object->stringProperty(), QString("Hello World!"));
266 QCOMPARE(object->uintProperty(), uint(10));
267 QCOMPARE(object->intProperty(), -19);
268 QCOMPARE((float)object->realProperty(), float(23.2));
269 QCOMPARE((float)object->doubleProperty(), float(-19.75));
270 QCOMPARE((float)object->floatProperty(), float(8.5));
271 QCOMPARE(object->colorProperty(), QColor("red"));
272 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
273 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
274 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
275 QCOMPARE(object->pointProperty(), QPoint(99,13));
276 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
277 QCOMPARE(object->sizeProperty(), QSize(99, 13));
278 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
279 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
280 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
281 QCOMPARE(object->boolProperty(), true);
282 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
283 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
284 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
289 void tst_qdeclarativeecmascript::idShortcutInvalidates()
292 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
293 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
294 QVERIFY(object != 0);
295 QVERIFY(object->objectProperty() != 0);
296 delete object->objectProperty();
297 QVERIFY(object->objectProperty() == 0);
302 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
303 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
304 QVERIFY(object != 0);
305 QVERIFY(object->objectProperty() != 0);
306 delete object->objectProperty();
307 QVERIFY(object->objectProperty() == 0);
312 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
315 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
316 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
317 QVERIFY(object != 0);
318 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
322 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
323 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
324 QVERIFY(object != 0);
325 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
330 void tst_qdeclarativeecmascript::signalAssignment()
333 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
334 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
335 QVERIFY(object != 0);
336 QCOMPARE(object->string(), QString());
337 emit object->basicSignal();
338 QCOMPARE(object->string(), QString("pass"));
343 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
344 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
345 QVERIFY(object != 0);
346 QCOMPARE(object->string(), QString());
347 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
348 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
353 void tst_qdeclarativeecmascript::methods()
356 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
357 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
358 QVERIFY(object != 0);
359 QCOMPARE(object->methodCalled(), false);
360 QCOMPARE(object->methodIntCalled(), false);
361 emit object->basicSignal();
362 QCOMPARE(object->methodCalled(), true);
363 QCOMPARE(object->methodIntCalled(), false);
368 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
369 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
370 QVERIFY(object != 0);
371 QCOMPARE(object->methodCalled(), false);
372 QCOMPARE(object->methodIntCalled(), false);
373 emit object->basicSignal();
374 QCOMPARE(object->methodCalled(), false);
375 QCOMPARE(object->methodIntCalled(), true);
380 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
381 QObject *object = component.create();
382 QVERIFY(object != 0);
383 QCOMPARE(object->property("test").toInt(), 19);
388 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
389 QObject *object = component.create();
390 QVERIFY(object != 0);
391 QCOMPARE(object->property("test").toInt(), 19);
392 QCOMPARE(object->property("test2").toInt(), 17);
393 QCOMPARE(object->property("test3").toInt(), 16);
398 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
399 QObject *object = component.create();
400 QVERIFY(object != 0);
401 QCOMPARE(object->property("test").toInt(), 9);
406 void tst_qdeclarativeecmascript::bindingLoop()
408 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
409 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
410 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
411 QObject *object = component.create();
412 QVERIFY(object != 0);
416 void tst_qdeclarativeecmascript::basicExpressions_data()
418 QTest::addColumn<QString>("expression");
419 QTest::addColumn<QVariant>("result");
420 QTest::addColumn<bool>("nest");
422 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
423 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
424 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
425 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
426 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
427 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
428 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
429 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
430 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
431 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
432 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
433 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
434 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
435 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
436 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
437 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
438 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
439 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
440 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
443 void tst_qdeclarativeecmascript::basicExpressions()
445 QFETCH(QString, expression);
446 QFETCH(QVariant, result);
452 MyDefaultObject1 default1;
453 MyDefaultObject3 default3;
454 object1.setStringProperty("Object1");
455 object2.setStringProperty("Object2");
456 object3.setStringProperty("Object3");
458 QDeclarativeContext context(engine.rootContext());
459 QDeclarativeContext nestedContext(&context);
461 context.setContextObject(&default1);
462 context.setContextProperty("a", QVariant(1944));
463 context.setContextProperty("b", QVariant("Milk"));
464 context.setContextProperty("object", &object1);
465 context.setContextProperty("objectOverride", &object2);
466 nestedContext.setContextObject(&default3);
467 nestedContext.setContextProperty("b", QVariant("Cow"));
468 nestedContext.setContextProperty("objectOverride", &object3);
469 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
471 MyExpression expr(nest?&nestedContext:&context, expression);
472 QCOMPARE(expr.evaluate(), result);
475 void tst_qdeclarativeecmascript::arrayExpressions()
481 QDeclarativeContext context(engine.rootContext());
482 context.setContextProperty("a", &obj1);
483 context.setContextProperty("b", &obj2);
484 context.setContextProperty("c", &obj3);
486 MyExpression expr(&context, "[a, b, c, 10]");
487 QVariant result = expr.evaluate();
488 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
489 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
490 QCOMPARE(list.count(), 4);
491 QCOMPARE(list.at(0), &obj1);
492 QCOMPARE(list.at(1), &obj2);
493 QCOMPARE(list.at(2), &obj3);
494 QCOMPARE(list.at(3), (QObject *)0);
497 // Tests that modifying a context property will reevaluate expressions
498 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
500 QDeclarativeContext context(engine.rootContext());
503 MyQmlObject *object3 = new MyQmlObject;
505 object1.setStringProperty("Hello");
506 object2.setStringProperty("World");
508 context.setContextProperty("testProp", QVariant(1));
509 context.setContextProperty("testObj", &object1);
510 context.setContextProperty("testObj2", object3);
513 MyExpression expr(&context, "testProp + 1");
514 QCOMPARE(expr.changed, false);
515 QCOMPARE(expr.evaluate(), QVariant(2));
517 context.setContextProperty("testProp", QVariant(2));
518 QCOMPARE(expr.changed, true);
519 QCOMPARE(expr.evaluate(), QVariant(3));
523 MyExpression expr(&context, "testProp + testProp + testProp");
524 QCOMPARE(expr.changed, false);
525 QCOMPARE(expr.evaluate(), QVariant(6));
527 context.setContextProperty("testProp", QVariant(4));
528 QCOMPARE(expr.changed, true);
529 QCOMPARE(expr.evaluate(), QVariant(12));
533 MyExpression expr(&context, "testObj.stringProperty");
534 QCOMPARE(expr.changed, false);
535 QCOMPARE(expr.evaluate(), QVariant("Hello"));
537 context.setContextProperty("testObj", &object2);
538 QCOMPARE(expr.changed, true);
539 QCOMPARE(expr.evaluate(), QVariant("World"));
543 MyExpression expr(&context, "testObj.stringProperty /**/");
544 QCOMPARE(expr.changed, false);
545 QCOMPARE(expr.evaluate(), QVariant("World"));
547 context.setContextProperty("testObj", &object1);
548 QCOMPARE(expr.changed, true);
549 QCOMPARE(expr.evaluate(), QVariant("Hello"));
553 MyExpression expr(&context, "testObj2");
554 QCOMPARE(expr.changed, false);
555 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
561 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
563 QDeclarativeContext context(engine.rootContext());
567 context.setContextProperty("testObj", &object1);
569 object1.setStringProperty(QLatin1String("Hello"));
570 object2.setStringProperty(QLatin1String("Dog"));
571 object3.setStringProperty(QLatin1String("Cat"));
574 MyExpression expr(&context, "testObj.stringProperty");
575 QCOMPARE(expr.changed, false);
576 QCOMPARE(expr.evaluate(), QVariant("Hello"));
578 object1.setStringProperty(QLatin1String("World"));
579 QCOMPARE(expr.changed, true);
580 QCOMPARE(expr.evaluate(), QVariant("World"));
584 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
585 QCOMPARE(expr.changed, false);
586 QCOMPARE(expr.evaluate(), QVariant());
588 object1.setObjectProperty(&object2);
589 QCOMPARE(expr.changed, true);
590 expr.changed = false;
591 QCOMPARE(expr.evaluate(), QVariant("Dog"));
593 object1.setObjectProperty(&object3);
594 QCOMPARE(expr.changed, true);
595 expr.changed = false;
596 QCOMPARE(expr.evaluate(), QVariant("Cat"));
598 object1.setObjectProperty(0);
599 QCOMPARE(expr.changed, true);
600 expr.changed = false;
601 QCOMPARE(expr.evaluate(), QVariant());
603 object1.setObjectProperty(&object3);
604 QCOMPARE(expr.changed, true);
605 expr.changed = false;
606 QCOMPARE(expr.evaluate(), QVariant("Cat"));
608 object3.setStringProperty("Donkey");
609 QCOMPARE(expr.changed, true);
610 expr.changed = false;
611 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
615 void tst_qdeclarativeecmascript::deferredProperties()
617 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
618 MyDeferredObject *object =
619 qobject_cast<MyDeferredObject *>(component.create());
620 QVERIFY(object != 0);
621 QCOMPARE(object->value(), 0);
622 QVERIFY(object->objectProperty() == 0);
623 QVERIFY(object->objectProperty2() != 0);
624 qmlExecuteDeferred(object);
625 QCOMPARE(object->value(), 10);
626 QVERIFY(object->objectProperty() != 0);
627 MyQmlObject *qmlObject =
628 qobject_cast<MyQmlObject *>(object->objectProperty());
629 QVERIFY(qmlObject != 0);
630 QCOMPARE(qmlObject->value(), 10);
631 object->setValue(19);
632 QCOMPARE(qmlObject->value(), 19);
637 // Check errors on deferred properties are correctly emitted
638 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
640 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.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);
648 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
649 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
651 qmlExecuteDeferred(object);
656 void tst_qdeclarativeecmascript::extensionObjects()
658 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
659 MyExtendedObject *object =
660 qobject_cast<MyExtendedObject *>(component.create());
661 QVERIFY(object != 0);
662 QCOMPARE(object->baseProperty(), 13);
663 QCOMPARE(object->coreProperty(), 9);
664 object->setProperty("extendedProperty", QVariant(11));
665 object->setProperty("baseExtendedProperty", QVariant(92));
666 QCOMPARE(object->coreProperty(), 11);
667 QCOMPARE(object->baseProperty(), 92);
669 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
671 QCOMPARE(nested->baseProperty(), 13);
672 QCOMPARE(nested->coreProperty(), 9);
673 nested->setProperty("extendedProperty", QVariant(11));
674 nested->setProperty("baseExtendedProperty", QVariant(92));
675 QCOMPARE(nested->coreProperty(), 11);
676 QCOMPARE(nested->baseProperty(), 92);
681 void tst_qdeclarativeecmascript::overrideExtensionProperties()
683 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
684 OverrideDefaultPropertyObject *object =
685 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
686 QVERIFY(object != 0);
687 QVERIFY(object->secondProperty() != 0);
688 QVERIFY(object->firstProperty() == 0);
693 void tst_qdeclarativeecmascript::attachedProperties()
696 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
697 QObject *object = component.create();
698 QVERIFY(object != 0);
699 QCOMPARE(object->property("a").toInt(), 19);
700 QCOMPARE(object->property("b").toInt(), 19);
701 QCOMPARE(object->property("c").toInt(), 19);
702 QCOMPARE(object->property("d").toInt(), 19);
707 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
708 QObject *object = component.create();
709 QVERIFY(object != 0);
710 QCOMPARE(object->property("a").toInt(), 26);
711 QCOMPARE(object->property("b").toInt(), 26);
712 QCOMPARE(object->property("c").toInt(), 26);
713 QCOMPARE(object->property("d").toInt(), 26);
719 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
720 QObject *object = component.create();
721 QVERIFY(object != 0);
723 QMetaObject::invokeMethod(object, "writeValue2");
725 MyQmlAttachedObject *attached =
726 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
727 QVERIFY(attached != 0);
729 QCOMPARE(attached->value2(), 9);
734 void tst_qdeclarativeecmascript::enums()
738 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
739 QObject *object = component.create();
740 QVERIFY(object != 0);
742 QCOMPARE(object->property("a").toInt(), 0);
743 QCOMPARE(object->property("b").toInt(), 1);
744 QCOMPARE(object->property("c").toInt(), 2);
745 QCOMPARE(object->property("d").toInt(), 3);
746 QCOMPARE(object->property("e").toInt(), 0);
747 QCOMPARE(object->property("f").toInt(), 1);
748 QCOMPARE(object->property("g").toInt(), 2);
749 QCOMPARE(object->property("h").toInt(), 3);
750 QCOMPARE(object->property("i").toInt(), 19);
751 QCOMPARE(object->property("j").toInt(), 19);
755 // Non-existent enums
757 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
759 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
760 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
761 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
762 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
764 QObject *object = component.create();
765 QVERIFY(object != 0);
766 QCOMPARE(object->property("a").toInt(), 0);
767 QCOMPARE(object->property("b").toInt(), 0);
773 void tst_qdeclarativeecmascript::valueTypeFunctions()
775 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
776 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
778 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
779 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
785 Tests that writing a constant to a property with a binding on it disables the
788 void tst_qdeclarativeecmascript::constantsOverrideBindings()
792 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
793 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
794 QVERIFY(object != 0);
796 QCOMPARE(object->property("c2").toInt(), 0);
797 object->setProperty("c1", QVariant(9));
798 QCOMPARE(object->property("c2").toInt(), 9);
800 emit object->basicSignal();
802 QCOMPARE(object->property("c2").toInt(), 13);
803 object->setProperty("c1", QVariant(8));
804 QCOMPARE(object->property("c2").toInt(), 13);
809 // During construction
811 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
812 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
813 QVERIFY(object != 0);
815 QCOMPARE(object->property("c1").toInt(), 0);
816 QCOMPARE(object->property("c2").toInt(), 10);
817 object->setProperty("c1", QVariant(9));
818 QCOMPARE(object->property("c1").toInt(), 9);
819 QCOMPARE(object->property("c2").toInt(), 10);
827 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
828 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
829 QVERIFY(object != 0);
831 QCOMPARE(object->property("c2").toInt(), 0);
832 object->setProperty("c1", QVariant(9));
833 QCOMPARE(object->property("c2").toInt(), 9);
835 object->setProperty("c2", QVariant(13));
836 QCOMPARE(object->property("c2").toInt(), 13);
837 object->setProperty("c1", QVariant(7));
838 QCOMPARE(object->property("c1").toInt(), 7);
839 QCOMPARE(object->property("c2").toInt(), 13);
847 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
848 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
849 QVERIFY(object != 0);
851 QCOMPARE(object->property("c1").toInt(), 0);
852 QCOMPARE(object->property("c3").toInt(), 10);
853 object->setProperty("c1", QVariant(9));
854 QCOMPARE(object->property("c1").toInt(), 9);
855 QCOMPARE(object->property("c3").toInt(), 10);
862 Tests that assigning a binding to a property that already has a binding causes
863 the original binding to be disabled.
865 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
867 QDeclarativeComponent component(&engine,
868 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
869 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
870 QVERIFY(object != 0);
872 QCOMPARE(object->property("c1").toInt(), 0);
873 QCOMPARE(object->property("c2").toInt(), 0);
874 QCOMPARE(object->property("c3").toInt(), 0);
876 object->setProperty("c1", QVariant(9));
877 QCOMPARE(object->property("c1").toInt(), 9);
878 QCOMPARE(object->property("c2").toInt(), 0);
879 QCOMPARE(object->property("c3").toInt(), 0);
881 object->setProperty("c3", QVariant(8));
882 QCOMPARE(object->property("c1").toInt(), 9);
883 QCOMPARE(object->property("c2").toInt(), 8);
884 QCOMPARE(object->property("c3").toInt(), 8);
890 Access a non-existent attached object.
892 Tests for a regression where this used to crash.
894 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
896 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
898 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
899 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
901 QObject *object = component.create();
902 QVERIFY(object != 0);
907 void tst_qdeclarativeecmascript::scope()
910 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
911 QObject *object = component.create();
912 QVERIFY(object != 0);
914 QCOMPARE(object->property("test1").toInt(), 1);
915 QCOMPARE(object->property("test2").toInt(), 2);
916 QCOMPARE(object->property("test3").toString(), QString("1Test"));
917 QCOMPARE(object->property("test4").toString(), QString("2Test"));
918 QCOMPARE(object->property("test5").toInt(), 1);
919 QCOMPARE(object->property("test6").toInt(), 1);
920 QCOMPARE(object->property("test7").toInt(), 2);
921 QCOMPARE(object->property("test8").toInt(), 2);
922 QCOMPARE(object->property("test9").toInt(), 1);
923 QCOMPARE(object->property("test10").toInt(), 3);
929 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
930 QObject *object = component.create();
931 QVERIFY(object != 0);
933 QCOMPARE(object->property("test1").toInt(), 19);
934 QCOMPARE(object->property("test2").toInt(), 19);
935 QCOMPARE(object->property("test3").toInt(), 14);
936 QCOMPARE(object->property("test4").toInt(), 14);
937 QCOMPARE(object->property("test5").toInt(), 24);
938 QCOMPARE(object->property("test6").toInt(), 24);
944 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
945 QObject *object = component.create();
946 QVERIFY(object != 0);
948 QCOMPARE(object->property("test1").toBool(), true);
949 QCOMPARE(object->property("test2").toBool(), true);
950 QCOMPARE(object->property("test3").toBool(), true);
955 // Signal argument scope
957 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
958 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
959 QVERIFY(object != 0);
961 QCOMPARE(object->property("test").toInt(), 0);
962 QCOMPARE(object->property("test2").toString(), QString());
964 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
966 QCOMPARE(object->property("test").toInt(), 13);
967 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
973 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
974 QObject *object = component.create();
975 QVERIFY(object != 0);
977 QCOMPARE(object->property("test1").toBool(), true);
978 QCOMPARE(object->property("test2").toBool(), true);
984 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
985 QObject *object = component.create();
986 QVERIFY(object != 0);
988 QCOMPARE(object->property("test").toBool(), true);
994 // In 4.7, non-library javascript files that had no imports shared the imports of their
996 void tst_qdeclarativeecmascript::importScope()
998 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
999 QObject *o = component.create();
1002 QCOMPARE(o->property("test").toInt(), 240);
1008 Tests that "any" type passes through a synthesized signal parameter. This
1009 is essentially a test of QDeclarativeMetaType::copy()
1011 void tst_qdeclarativeecmascript::signalParameterTypes()
1013 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1014 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1015 QVERIFY(object != 0);
1017 emit object->basicSignal();
1019 QCOMPARE(object->property("intProperty").toInt(), 10);
1020 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1021 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1022 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1023 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1024 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1030 Test that two JS objects for the same QObject compare as equal.
1032 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1034 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1035 QObject *object = component.create();
1036 QVERIFY(object != 0);
1038 QCOMPARE(object->property("test1").toBool(), true);
1039 QCOMPARE(object->property("test2").toBool(), true);
1040 QCOMPARE(object->property("test3").toBool(), true);
1041 QCOMPARE(object->property("test4").toBool(), true);
1042 QCOMPARE(object->property("test5").toBool(), true);
1048 Confirm bindings and alias properties can coexist.
1050 Tests for a regression where the binding would not reevaluate.
1052 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1054 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1055 QObject *object = component.create();
1056 QVERIFY(object != 0);
1058 QCOMPARE(object->property("c2").toInt(), 3);
1059 QCOMPARE(object->property("c3").toInt(), 3);
1061 object->setProperty("c2", QVariant(19));
1063 QCOMPARE(object->property("c2").toInt(), 19);
1064 QCOMPARE(object->property("c3").toInt(), 19);
1070 Ensure that we can write undefined value to an alias property,
1071 and that the aliased property is reset correctly if possible.
1073 void tst_qdeclarativeecmascript::aliasPropertyReset()
1075 QObject *object = 0;
1077 // test that a manual write (of undefined) to a resettable aliased property succeeds
1078 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1079 object = c1.create();
1080 QVERIFY(object != 0);
1081 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1082 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1083 QMetaObject::invokeMethod(object, "resetAliased");
1084 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1085 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1088 // test that a manual write (of undefined) to a resettable alias property succeeds
1089 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1090 object = c2.create();
1091 QVERIFY(object != 0);
1092 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1093 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1094 QMetaObject::invokeMethod(object, "resetAlias");
1095 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1096 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1099 // test that an alias to a bound property works correctly
1100 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1101 object = c3.create();
1102 QVERIFY(object != 0);
1103 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1104 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1105 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1106 QMetaObject::invokeMethod(object, "resetAlias");
1107 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1108 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1109 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1112 // test that a manual write (of undefined) to a resettable alias property
1113 // whose aliased property's object has been deleted, does not crash.
1114 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1115 object = c4.create();
1116 QVERIFY(object != 0);
1117 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1118 QObject *loader = object->findChild<QObject*>("loader");
1119 QVERIFY(loader != 0);
1121 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1122 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1123 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1124 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1125 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1128 // test that binding an alias property to an undefined value works correctly
1129 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1130 object = c5.create();
1131 QVERIFY(object != 0);
1132 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1135 // test that a manual write (of undefined) to a non-resettable property fails properly
1136 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1137 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1138 QDeclarativeComponent e1(&engine, url);
1139 object = e1.create();
1140 QVERIFY(object != 0);
1141 QCOMPARE(object->property("intAlias").value<int>(), 12);
1142 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1143 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1144 QMetaObject::invokeMethod(object, "resetAlias");
1145 QCOMPARE(object->property("intAlias").value<int>(), 12);
1146 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1150 void tst_qdeclarativeecmascript::dynamicCreation_data()
1152 QTest::addColumn<QString>("method");
1153 QTest::addColumn<QString>("createdName");
1155 QTest::newRow("One") << "createOne" << "objectOne";
1156 QTest::newRow("Two") << "createTwo" << "objectTwo";
1157 QTest::newRow("Three") << "createThree" << "objectThree";
1161 Test using createQmlObject to dynamically generate an item
1162 Also using createComponent is tested.
1164 void tst_qdeclarativeecmascript::dynamicCreation()
1166 QFETCH(QString, method);
1167 QFETCH(QString, createdName);
1169 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1170 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1171 QVERIFY(object != 0);
1173 QMetaObject::invokeMethod(object, method.toUtf8());
1174 QObject *created = object->objectProperty();
1176 QCOMPARE(created->objectName(), createdName);
1182 Tests the destroy function
1184 void tst_qdeclarativeecmascript::dynamicDestruction()
1187 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1188 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1189 QVERIFY(object != 0);
1190 QDeclarativeGuard<QObject> createdQmlObject = 0;
1192 QMetaObject::invokeMethod(object, "create");
1193 createdQmlObject = object->objectProperty();
1194 QVERIFY(createdQmlObject);
1195 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1197 QMetaObject::invokeMethod(object, "killOther");
1198 QVERIFY(createdQmlObject);
1199 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1200 QVERIFY(createdQmlObject);
1201 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1202 if (createdQmlObject) {
1204 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1207 QVERIFY(!createdQmlObject);
1209 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1210 QMetaObject::invokeMethod(object, "killMe");
1213 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1218 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1219 QObject *o = component.create();
1222 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1224 QMetaObject::invokeMethod(o, "create");
1226 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1228 QMetaObject::invokeMethod(o, "destroy");
1230 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1232 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1239 tests that id.toString() works
1241 void tst_qdeclarativeecmascript::objectToString()
1243 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1244 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1245 QVERIFY(object != 0);
1246 QMetaObject::invokeMethod(object, "testToString");
1247 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1248 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1254 tests that id.hasOwnProperty() works
1256 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1258 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1259 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1260 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1261 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1263 QDeclarativeComponent component(&engine, url);
1264 QObject *object = component.create();
1265 QVERIFY(object != 0);
1267 // test QObjects in QML
1268 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1269 QVERIFY(object->property("result").value<bool>() == true);
1270 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1271 QVERIFY(object->property("result").value<bool>() == false);
1273 // now test other types in QML
1274 QObject *child = object->findChild<QObject*>("typeObj");
1275 QVERIFY(child != 0);
1276 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1277 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1278 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1279 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1280 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1281 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1282 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1283 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1284 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1285 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1286 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1287 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1289 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1290 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1291 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1292 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1293 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1294 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1295 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1296 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1297 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1303 Tests bindings that indirectly cause their own deletion work.
1305 This test is best run under valgrind to ensure no invalid memory access occur.
1307 void tst_qdeclarativeecmascript::selfDeletingBinding()
1310 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1311 QObject *object = component.create();
1312 QVERIFY(object != 0);
1313 object->setProperty("triggerDelete", true);
1318 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1319 QObject *object = component.create();
1320 QVERIFY(object != 0);
1321 object->setProperty("triggerDelete", true);
1327 Test that extended object properties can be accessed.
1329 This test a regression where this used to crash. The issue was specificially
1330 for extended objects that did not include a synthesized meta object (so non-root
1331 and no synthesiszed properties).
1333 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1335 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1336 QObject *object = component.create();
1337 QVERIFY(object != 0);
1342 Test file/lineNumbers for binding/Script errors.
1344 void tst_qdeclarativeecmascript::scriptErrors()
1346 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1347 QString url = component.url().toString();
1349 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1350 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1351 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1352 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1353 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1354 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1355 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1356 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1358 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1359 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1360 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1361 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1362 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1363 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1364 QVERIFY(object != 0);
1366 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1367 emit object->basicSignal();
1369 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1370 emit object->anotherBasicSignal();
1372 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1373 emit object->thirdBasicSignal();
1379 Test file/lineNumbers for inline functions.
1381 void tst_qdeclarativeecmascript::functionErrors()
1383 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1384 QString url = component.url().toString();
1386 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1388 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1390 QObject *object = component.create();
1391 QVERIFY(object != 0);
1394 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1395 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1396 url = componentTwo.url().toString();
1397 object = componentTwo.create();
1398 QVERIFY(object != 0);
1400 QString srpname = object->property("srp_name").toString();
1402 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1403 QLatin1String(" is not a function");
1404 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1405 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1410 Test various errors that can occur when assigning a property from script
1412 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1414 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1416 QString url = component.url().toString();
1418 QObject *object = component.create();
1419 QVERIFY(object != 0);
1421 QCOMPARE(object->property("test1").toBool(), true);
1422 QCOMPARE(object->property("test2").toBool(), true);
1428 Test bindings still work when the reeval is triggered from within
1431 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1433 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1434 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1435 QVERIFY(object != 0);
1437 QCOMPARE(object->property("base").toReal(), 50.);
1438 QCOMPARE(object->property("test1").toReal(), 50.);
1439 QCOMPARE(object->property("test2").toReal(), 50.);
1441 object->basicSignal();
1443 QCOMPARE(object->property("base").toReal(), 200.);
1444 QCOMPARE(object->property("test1").toReal(), 200.);
1445 QCOMPARE(object->property("test2").toReal(), 200.);
1447 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1449 QCOMPARE(object->property("base").toReal(), 400.);
1450 QCOMPARE(object->property("test1").toReal(), 400.);
1451 QCOMPARE(object->property("test2").toReal(), 400.);
1457 Test that list properties can be iterated from ECMAScript
1459 void tst_qdeclarativeecmascript::listProperties()
1461 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1462 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1463 QVERIFY(object != 0);
1465 QCOMPARE(object->property("test1").toInt(), 21);
1466 QCOMPARE(object->property("test2").toInt(), 2);
1467 QCOMPARE(object->property("test3").toBool(), true);
1468 QCOMPARE(object->property("test4").toBool(), true);
1473 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1475 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1476 QString url = component.url().toString();
1478 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1480 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1481 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1482 QVERIFY(object != 0);
1484 QCOMPARE(object->property("test").toBool(), false);
1486 MyQmlObject object2;
1487 MyQmlObject object3;
1488 object2.setObjectProperty(&object3);
1489 object->setObjectProperty(&object2);
1491 QCOMPARE(object->property("test").toBool(), true);
1496 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1498 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1499 QString url = component.url().toString();
1501 QString warning = component.url().toString() + ":6: Error: JS exception";
1503 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1504 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1505 QVERIFY(object != 0);
1509 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1511 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1512 QString url = component.url().toString();
1514 QString warning = component.url().toString() + ":5: Error: JS exception";
1516 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1517 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1518 QVERIFY(object != 0);
1522 static int transientErrorsMsgCount = 0;
1523 static void transientErrorsMsgHandler(QtMsgType, const char *)
1525 ++transientErrorsMsgCount;
1528 // Check that transient binding errors are not displayed
1529 void tst_qdeclarativeecmascript::transientErrors()
1532 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1534 transientErrorsMsgCount = 0;
1535 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1537 QObject *object = component.create();
1538 QVERIFY(object != 0);
1540 qInstallMsgHandler(old);
1542 QCOMPARE(transientErrorsMsgCount, 0);
1547 // One binding erroring multiple times, but then resolving
1549 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1551 transientErrorsMsgCount = 0;
1552 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1554 QObject *object = component.create();
1555 QVERIFY(object != 0);
1557 qInstallMsgHandler(old);
1559 QCOMPARE(transientErrorsMsgCount, 0);
1565 // Check that errors during shutdown are minimized
1566 void tst_qdeclarativeecmascript::shutdownErrors()
1568 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1569 QObject *object = component.create();
1570 QVERIFY(object != 0);
1572 transientErrorsMsgCount = 0;
1573 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1577 qInstallMsgHandler(old);
1578 QCOMPARE(transientErrorsMsgCount, 0);
1581 void tst_qdeclarativeecmascript::compositePropertyType()
1583 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1584 QTest::ignoreMessage(QtDebugMsg, "hello world");
1585 QObject *object = qobject_cast<QObject *>(component.create());
1590 void tst_qdeclarativeecmascript::jsObject()
1592 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1593 QObject *object = component.create();
1594 QVERIFY(object != 0);
1596 QCOMPARE(object->property("test").toInt(), 92);
1601 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1604 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1605 QObject *object = component.create();
1606 QVERIFY(object != 0);
1608 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1610 object->setProperty("setUndefined", true);
1612 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1614 object->setProperty("setUndefined", false);
1616 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1621 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1622 QObject *object = component.create();
1623 QVERIFY(object != 0);
1625 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1627 QMetaObject::invokeMethod(object, "doReset");
1629 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1636 void tst_qdeclarativeecmascript::bug1()
1638 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1639 QObject *object = component.create();
1640 QVERIFY(object != 0);
1642 QCOMPARE(object->property("test").toInt(), 14);
1644 object->setProperty("a", 11);
1646 QCOMPARE(object->property("test").toInt(), 3);
1648 object->setProperty("b", true);
1650 QCOMPARE(object->property("test").toInt(), 9);
1655 void tst_qdeclarativeecmascript::bug2()
1657 QDeclarativeComponent component(&engine);
1658 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1660 QObject *object = component.create();
1661 QVERIFY(object != 0);
1666 // Don't crash in createObject when the component has errors.
1667 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1669 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1670 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1671 QVERIFY(object != 0);
1673 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1674 QMetaObject::invokeMethod(object, "dontCrash");
1675 QObject *created = object->objectProperty();
1676 QVERIFY(created == 0);
1681 // ownership transferred to JS, ensure that GC runs the dtor
1682 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1685 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1687 // allow the engine to go out of scope too.
1689 QDeclarativeEngine dcoEngine;
1690 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1691 QObject *object = component.create();
1692 QVERIFY(object != 0);
1693 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1694 QVERIFY(mdcdo != 0);
1695 mdcdo->setDtorCount(&dtorCount);
1697 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1698 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1700 // we do this once manually, but it should be done automatically
1701 // when the engine goes out of scope (since it should gc in dtor)
1702 QMetaObject::invokeMethod(object, "performGc");
1705 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1711 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1712 QCOMPARE(dtorCount, expectedDtorCount);
1716 void tst_qdeclarativeecmascript::regExpBug()
1718 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1719 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1720 QVERIFY(object != 0);
1721 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1725 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1727 QString functionSource = QLatin1String("(function(object) { return ") +
1728 QLatin1String(source) + QLatin1String(" })");
1730 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1733 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1734 if (function.IsEmpty())
1736 v8::Handle<v8::Value> args[] = { o };
1737 function->Call(engine->global(), 1, args);
1738 return tc.HasCaught();
1741 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1742 const char *source, v8::Handle<v8::Value> result)
1744 QString functionSource = QLatin1String("(function(object) { return ") +
1745 QLatin1String(source) + QLatin1String(" })");
1747 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1750 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1751 if (function.IsEmpty())
1753 v8::Handle<v8::Value> args[] = { o };
1755 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1760 return value->StrictEquals(result);
1763 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1766 QString functionSource = QLatin1String("(function(object) { return ") +
1767 QLatin1String(source) + QLatin1String(" })");
1769 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1771 return v8::Handle<v8::Value>();
1772 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1773 if (function.IsEmpty())
1774 return v8::Handle<v8::Value>();
1775 v8::Handle<v8::Value> args[] = { o };
1777 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1780 return v8::Handle<v8::Value>();
1784 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1785 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1786 #define EVALUATE(source) evaluate(engine, object, source)
1788 void tst_qdeclarativeecmascript::callQtInvokables()
1790 MyInvokableObject o;
1792 QDeclarativeEngine qmlengine;
1793 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1795 QV8Engine *engine = ep->v8engine();
1797 v8::HandleScope handle_scope;
1798 v8::Context::Scope scope(engine->context());
1800 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1802 // Non-existent methods
1804 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1805 QCOMPARE(o.error(), false);
1806 QCOMPARE(o.invoked(), -1);
1807 QCOMPARE(o.actuals().count(), 0);
1810 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1811 QCOMPARE(o.error(), false);
1812 QCOMPARE(o.invoked(), -1);
1813 QCOMPARE(o.actuals().count(), 0);
1815 // Insufficient arguments
1817 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1818 QCOMPARE(o.error(), false);
1819 QCOMPARE(o.invoked(), -1);
1820 QCOMPARE(o.actuals().count(), 0);
1823 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1824 QCOMPARE(o.error(), false);
1825 QCOMPARE(o.invoked(), -1);
1826 QCOMPARE(o.actuals().count(), 0);
1828 // Excessive arguments
1830 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1831 QCOMPARE(o.error(), false);
1832 QCOMPARE(o.invoked(), 8);
1833 QCOMPARE(o.actuals().count(), 1);
1834 QCOMPARE(o.actuals().at(0), QVariant(10));
1837 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1838 QCOMPARE(o.error(), false);
1839 QCOMPARE(o.invoked(), 9);
1840 QCOMPARE(o.actuals().count(), 2);
1841 QCOMPARE(o.actuals().at(0), QVariant(10));
1842 QCOMPARE(o.actuals().at(1), QVariant(11));
1844 // Test return types
1846 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1847 QCOMPARE(o.error(), false);
1848 QCOMPARE(o.invoked(), 0);
1849 QCOMPARE(o.actuals().count(), 0);
1852 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1853 QCOMPARE(o.error(), false);
1854 QCOMPARE(o.invoked(), 1);
1855 QCOMPARE(o.actuals().count(), 0);
1858 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1859 QCOMPARE(o.error(), false);
1860 QCOMPARE(o.invoked(), 2);
1861 QCOMPARE(o.actuals().count(), 0);
1865 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1866 QVERIFY(!ret.IsEmpty());
1867 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1868 QCOMPARE(o.error(), false);
1869 QCOMPARE(o.invoked(), 3);
1870 QCOMPARE(o.actuals().count(), 0);
1875 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1876 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1877 QCOMPARE(o.error(), false);
1878 QCOMPARE(o.invoked(), 4);
1879 QCOMPARE(o.actuals().count(), 0);
1883 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1884 QCOMPARE(o.error(), false);
1885 QCOMPARE(o.invoked(), 5);
1886 QCOMPARE(o.actuals().count(), 0);
1890 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1891 QVERIFY(ret->IsString());
1892 QCOMPARE(engine->toString(ret), QString("Hello world"));
1893 QCOMPARE(o.error(), false);
1894 QCOMPARE(o.invoked(), 6);
1895 QCOMPARE(o.actuals().count(), 0);
1899 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1900 QCOMPARE(o.error(), false);
1901 QCOMPARE(o.invoked(), 7);
1902 QCOMPARE(o.actuals().count(), 0);
1906 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1907 QCOMPARE(o.error(), false);
1908 QCOMPARE(o.invoked(), 8);
1909 QCOMPARE(o.actuals().count(), 1);
1910 QCOMPARE(o.actuals().at(0), QVariant(94));
1913 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1914 QCOMPARE(o.error(), false);
1915 QCOMPARE(o.invoked(), 8);
1916 QCOMPARE(o.actuals().count(), 1);
1917 QCOMPARE(o.actuals().at(0), QVariant(94));
1920 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1921 QCOMPARE(o.error(), false);
1922 QCOMPARE(o.invoked(), 8);
1923 QCOMPARE(o.actuals().count(), 1);
1924 QCOMPARE(o.actuals().at(0), QVariant(0));
1927 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1928 QCOMPARE(o.error(), false);
1929 QCOMPARE(o.invoked(), 8);
1930 QCOMPARE(o.actuals().count(), 1);
1931 QCOMPARE(o.actuals().at(0), QVariant(0));
1934 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1935 QCOMPARE(o.error(), false);
1936 QCOMPARE(o.invoked(), 8);
1937 QCOMPARE(o.actuals().count(), 1);
1938 QCOMPARE(o.actuals().at(0), QVariant(0));
1941 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1942 QCOMPARE(o.error(), false);
1943 QCOMPARE(o.invoked(), 8);
1944 QCOMPARE(o.actuals().count(), 1);
1945 QCOMPARE(o.actuals().at(0), QVariant(0));
1948 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1949 QCOMPARE(o.error(), false);
1950 QCOMPARE(o.invoked(), 9);
1951 QCOMPARE(o.actuals().count(), 2);
1952 QCOMPARE(o.actuals().at(0), QVariant(122));
1953 QCOMPARE(o.actuals().at(1), QVariant(9));
1956 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1957 QCOMPARE(o.error(), false);
1958 QCOMPARE(o.invoked(), 10);
1959 QCOMPARE(o.actuals().count(), 1);
1960 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1963 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1964 QCOMPARE(o.error(), false);
1965 QCOMPARE(o.invoked(), 10);
1966 QCOMPARE(o.actuals().count(), 1);
1967 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1970 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1971 QCOMPARE(o.error(), false);
1972 QCOMPARE(o.invoked(), 10);
1973 QCOMPARE(o.actuals().count(), 1);
1974 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1977 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1978 QCOMPARE(o.error(), false);
1979 QCOMPARE(o.invoked(), 10);
1980 QCOMPARE(o.actuals().count(), 1);
1981 QCOMPARE(o.actuals().at(0), QVariant(0));
1984 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1985 QCOMPARE(o.error(), false);
1986 QCOMPARE(o.invoked(), 10);
1987 QCOMPARE(o.actuals().count(), 1);
1988 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1991 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1992 QCOMPARE(o.error(), false);
1993 QCOMPARE(o.invoked(), 10);
1994 QCOMPARE(o.actuals().count(), 1);
1995 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1998 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1999 QCOMPARE(o.error(), false);
2000 QCOMPARE(o.invoked(), 11);
2001 QCOMPARE(o.actuals().count(), 1);
2002 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2005 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2006 QCOMPARE(o.error(), false);
2007 QCOMPARE(o.invoked(), 11);
2008 QCOMPARE(o.actuals().count(), 1);
2009 QCOMPARE(o.actuals().at(0), QVariant("19"));
2013 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2014 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2015 QCOMPARE(o.error(), false);
2016 QCOMPARE(o.invoked(), 11);
2017 QCOMPARE(o.actuals().count(), 1);
2018 QCOMPARE(o.actuals().at(0), QVariant(expected));
2022 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2023 QCOMPARE(o.error(), false);
2024 QCOMPARE(o.invoked(), 11);
2025 QCOMPARE(o.actuals().count(), 1);
2026 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2029 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2030 QCOMPARE(o.error(), false);
2031 QCOMPARE(o.invoked(), 11);
2032 QCOMPARE(o.actuals().count(), 1);
2033 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2036 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2037 QCOMPARE(o.error(), false);
2038 QCOMPARE(o.invoked(), 12);
2039 QCOMPARE(o.actuals().count(), 1);
2040 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2043 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2044 QCOMPARE(o.error(), false);
2045 QCOMPARE(o.invoked(), 12);
2046 QCOMPARE(o.actuals().count(), 1);
2047 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2050 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2051 QCOMPARE(o.error(), false);
2052 QCOMPARE(o.invoked(), 12);
2053 QCOMPARE(o.actuals().count(), 1);
2054 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2057 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2058 QCOMPARE(o.error(), false);
2059 QCOMPARE(o.invoked(), 12);
2060 QCOMPARE(o.actuals().count(), 1);
2061 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2064 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2065 QCOMPARE(o.error(), false);
2066 QCOMPARE(o.invoked(), 12);
2067 QCOMPARE(o.actuals().count(), 1);
2068 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2071 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2072 QCOMPARE(o.error(), false);
2073 QCOMPARE(o.invoked(), 12);
2074 QCOMPARE(o.actuals().count(), 1);
2075 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2078 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2079 QCOMPARE(o.error(), false);
2080 QCOMPARE(o.invoked(), 13);
2081 QCOMPARE(o.actuals().count(), 1);
2082 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2085 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2086 QCOMPARE(o.error(), false);
2087 QCOMPARE(o.invoked(), 13);
2088 QCOMPARE(o.actuals().count(), 1);
2089 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2092 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2093 QCOMPARE(o.error(), false);
2094 QCOMPARE(o.invoked(), 13);
2095 QCOMPARE(o.actuals().count(), 1);
2096 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2099 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2100 QCOMPARE(o.error(), false);
2101 QCOMPARE(o.invoked(), 13);
2102 QCOMPARE(o.actuals().count(), 1);
2103 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2106 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2107 QCOMPARE(o.error(), false);
2108 QCOMPARE(o.invoked(), 13);
2109 QCOMPARE(o.actuals().count(), 1);
2110 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2113 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2114 QCOMPARE(o.error(), false);
2115 QCOMPARE(o.invoked(), 14);
2116 QCOMPARE(o.actuals().count(), 1);
2117 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2120 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2121 QCOMPARE(o.error(), false);
2122 QCOMPARE(o.invoked(), 14);
2123 QCOMPARE(o.actuals().count(), 1);
2124 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2127 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2128 QCOMPARE(o.error(), false);
2129 QCOMPARE(o.invoked(), 14);
2130 QCOMPARE(o.actuals().count(), 1);
2131 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2134 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2135 QCOMPARE(o.error(), false);
2136 QCOMPARE(o.invoked(), 14);
2137 QCOMPARE(o.actuals().count(), 1);
2138 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2141 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2142 QCOMPARE(o.error(), false);
2143 QCOMPARE(o.invoked(), 15);
2144 QCOMPARE(o.actuals().count(), 2);
2145 QCOMPARE(o.actuals().at(0), QVariant(4));
2146 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2149 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2150 QCOMPARE(o.error(), false);
2151 QCOMPARE(o.invoked(), 15);
2152 QCOMPARE(o.actuals().count(), 2);
2153 QCOMPARE(o.actuals().at(0), QVariant(8));
2154 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2157 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2158 QCOMPARE(o.error(), false);
2159 QCOMPARE(o.invoked(), 15);
2160 QCOMPARE(o.actuals().count(), 2);
2161 QCOMPARE(o.actuals().at(0), QVariant(3));
2162 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2165 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2166 QCOMPARE(o.error(), false);
2167 QCOMPARE(o.invoked(), 15);
2168 QCOMPARE(o.actuals().count(), 2);
2169 QCOMPARE(o.actuals().at(0), QVariant(44));
2170 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2173 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2174 QCOMPARE(o.error(), false);
2175 QCOMPARE(o.invoked(), -1);
2176 QCOMPARE(o.actuals().count(), 0);
2179 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2180 QCOMPARE(o.error(), false);
2181 QCOMPARE(o.invoked(), 16);
2182 QCOMPARE(o.actuals().count(), 1);
2183 QCOMPARE(o.actuals().at(0), QVariant(10));
2186 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2187 QCOMPARE(o.error(), false);
2188 QCOMPARE(o.invoked(), 17);
2189 QCOMPARE(o.actuals().count(), 2);
2190 QCOMPARE(o.actuals().at(0), QVariant(10));
2191 QCOMPARE(o.actuals().at(1), QVariant(11));
2194 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2195 QCOMPARE(o.error(), false);
2196 QCOMPARE(o.invoked(), 18);
2197 QCOMPARE(o.actuals().count(), 1);
2198 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2201 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2202 QCOMPARE(o.error(), false);
2203 QCOMPARE(o.invoked(), 19);
2204 QCOMPARE(o.actuals().count(), 1);
2205 QCOMPARE(o.actuals().at(0), QVariant(9));
2208 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2209 QCOMPARE(o.error(), false);
2210 QCOMPARE(o.invoked(), 20);
2211 QCOMPARE(o.actuals().count(), 2);
2212 QCOMPARE(o.actuals().at(0), QVariant(10));
2213 QCOMPARE(o.actuals().at(1), QVariant(19));
2216 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2217 QCOMPARE(o.error(), false);
2218 QCOMPARE(o.invoked(), 20);
2219 QCOMPARE(o.actuals().count(), 2);
2220 QCOMPARE(o.actuals().at(0), QVariant(10));
2221 QCOMPARE(o.actuals().at(1), QVariant(13));
2224 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2225 QCOMPARE(o.error(), false);
2226 QCOMPARE(o.invoked(), -3);
2227 QCOMPARE(o.actuals().count(), 1);
2228 QCOMPARE(o.actuals().at(0), QVariant(9));
2231 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2232 QCOMPARE(o.error(), false);
2233 QCOMPARE(o.invoked(), 21);
2234 QCOMPARE(o.actuals().count(), 2);
2235 QCOMPARE(o.actuals().at(0), QVariant(9));
2236 QCOMPARE(o.actuals().at(1), QVariant());
2239 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2240 QCOMPARE(o.error(), false);
2241 QCOMPARE(o.invoked(), 21);
2242 QCOMPARE(o.actuals().count(), 2);
2243 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2244 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2247 // QTBUG-13047 (check that you can pass registered object types as args)
2248 void tst_qdeclarativeecmascript::invokableObjectArg()
2250 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2252 QObject *o = component.create();
2254 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2256 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2261 // QTBUG-13047 (check that you can return registered object types from methods)
2262 void tst_qdeclarativeecmascript::invokableObjectRet()
2264 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2266 QObject *o = component.create();
2268 QCOMPARE(o->property("test").toBool(), true);
2273 void tst_qdeclarativeecmascript::listToVariant()
2275 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2277 MyQmlContainer container;
2279 QDeclarativeContext context(engine.rootContext());
2280 context.setContextObject(&container);
2282 QObject *object = component.create(&context);
2283 QVERIFY(object != 0);
2285 QVariant v = object->property("test");
2286 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2287 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2293 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2294 void tst_qdeclarativeecmascript::listAssignment()
2296 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2297 QObject *obj = component.create();
2298 QCOMPARE(obj->property("list1length").toInt(), 2);
2299 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2300 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2301 QCOMPARE(list1.count(&list1), list2.count(&list2));
2302 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2303 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2308 void tst_qdeclarativeecmascript::multiEngineObject()
2311 obj.setStringProperty("Howdy planet");
2313 QDeclarativeEngine e1;
2314 e1.rootContext()->setContextProperty("thing", &obj);
2315 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2317 QDeclarativeEngine e2;
2318 e2.rootContext()->setContextProperty("thing", &obj);
2319 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2321 QObject *o1 = c1.create();
2322 QObject *o2 = c2.create();
2324 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2325 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2331 // Test that references to QObjects are cleanup when the object is destroyed
2332 void tst_qdeclarativeecmascript::deletedObject()
2334 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2336 QObject *object = component.create();
2338 QCOMPARE(object->property("test1").toBool(), true);
2339 QCOMPARE(object->property("test2").toBool(), true);
2340 QCOMPARE(object->property("test3").toBool(), true);
2341 QCOMPARE(object->property("test4").toBool(), true);
2346 void tst_qdeclarativeecmascript::attachedPropertyScope()
2348 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2350 QObject *object = component.create();
2351 QVERIFY(object != 0);
2353 MyQmlAttachedObject *attached =
2354 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2355 QVERIFY(attached != 0);
2357 QCOMPARE(object->property("value2").toInt(), 0);
2359 attached->emitMySignal();
2361 QCOMPARE(object->property("value2").toInt(), 9);
2366 void tst_qdeclarativeecmascript::scriptConnect()
2369 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2371 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2372 QVERIFY(object != 0);
2374 QCOMPARE(object->property("test").toBool(), false);
2375 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2376 QCOMPARE(object->property("test").toBool(), true);
2382 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2384 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2385 QVERIFY(object != 0);
2387 QCOMPARE(object->property("test").toBool(), false);
2388 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2389 QCOMPARE(object->property("test").toBool(), true);
2395 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2397 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2398 QVERIFY(object != 0);
2400 QCOMPARE(object->property("test").toBool(), false);
2401 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2402 QCOMPARE(object->property("test").toBool(), true);
2408 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2410 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2411 QVERIFY(object != 0);
2413 QCOMPARE(object->methodCalled(), false);
2414 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2415 QCOMPARE(object->methodCalled(), true);
2421 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2423 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2424 QVERIFY(object != 0);
2426 QCOMPARE(object->methodCalled(), false);
2427 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2428 QCOMPARE(object->methodCalled(), true);
2434 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2436 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2437 QVERIFY(object != 0);
2439 QCOMPARE(object->property("test").toInt(), 0);
2440 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2441 QCOMPARE(object->property("test").toInt(), 2);
2447 void tst_qdeclarativeecmascript::scriptDisconnect()
2450 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2452 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2453 QVERIFY(object != 0);
2455 QCOMPARE(object->property("test").toInt(), 0);
2456 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2457 QCOMPARE(object->property("test").toInt(), 1);
2458 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2459 QCOMPARE(object->property("test").toInt(), 2);
2460 emit object->basicSignal();
2461 QCOMPARE(object->property("test").toInt(), 2);
2462 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2463 QCOMPARE(object->property("test").toInt(), 2);
2469 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2471 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2472 QVERIFY(object != 0);
2474 QCOMPARE(object->property("test").toInt(), 0);
2475 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2476 QCOMPARE(object->property("test").toInt(), 1);
2477 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2478 QCOMPARE(object->property("test").toInt(), 2);
2479 emit object->basicSignal();
2480 QCOMPARE(object->property("test").toInt(), 2);
2481 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2482 QCOMPARE(object->property("test").toInt(), 2);
2488 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2490 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2491 QVERIFY(object != 0);
2493 QCOMPARE(object->property("test").toInt(), 0);
2494 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2495 QCOMPARE(object->property("test").toInt(), 1);
2496 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2497 QCOMPARE(object->property("test").toInt(), 2);
2498 emit object->basicSignal();
2499 QCOMPARE(object->property("test").toInt(), 2);
2500 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2501 QCOMPARE(object->property("test").toInt(), 3);
2506 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2508 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2509 QVERIFY(object != 0);
2511 QCOMPARE(object->property("test").toInt(), 0);
2512 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2513 QCOMPARE(object->property("test").toInt(), 1);
2514 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2515 QCOMPARE(object->property("test").toInt(), 2);
2516 emit object->basicSignal();
2517 QCOMPARE(object->property("test").toInt(), 2);
2518 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2519 QCOMPARE(object->property("test").toInt(), 3);
2525 class OwnershipObject : public QObject
2529 OwnershipObject() { object = new QObject; }
2531 QPointer<QObject> object;
2534 QObject *getObject() { return object; }
2537 void tst_qdeclarativeecmascript::ownership()
2539 OwnershipObject own;
2540 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2541 context->setContextObject(&own);
2544 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2546 QVERIFY(own.object != 0);
2548 QObject *object = component.create(context);
2550 engine.collectGarbage();
2552 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2554 QVERIFY(own.object == 0);
2559 own.object = new QObject(&own);
2562 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2564 QVERIFY(own.object != 0);
2566 QObject *object = component.create(context);
2568 engine.collectGarbage();
2570 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2572 QVERIFY(own.object != 0);
2580 class CppOwnershipReturnValue : public QObject
2584 CppOwnershipReturnValue() : value(0) {}
2585 ~CppOwnershipReturnValue() { delete value; }
2587 Q_INVOKABLE QObject *create() {
2588 value = new QObject;
2589 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2593 Q_INVOKABLE MyQmlObject *createQmlObject() {
2594 MyQmlObject *rv = new MyQmlObject;
2599 QPointer<QObject> value;
2603 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2604 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2606 CppOwnershipReturnValue source;
2609 QDeclarativeEngine engine;
2610 engine.rootContext()->setContextProperty("source", &source);
2612 QVERIFY(source.value == 0);
2614 QDeclarativeComponent component(&engine);
2615 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2617 QObject *object = component.create();
2619 QVERIFY(object != 0);
2620 QVERIFY(source.value != 0);
2625 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2627 QVERIFY(source.value != 0);
2631 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2633 CppOwnershipReturnValue source;
2636 QDeclarativeEngine engine;
2637 engine.rootContext()->setContextProperty("source", &source);
2639 QVERIFY(source.value == 0);
2641 QDeclarativeComponent component(&engine);
2642 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2644 QObject *object = component.create();
2646 QVERIFY(object != 0);
2647 QVERIFY(source.value != 0);
2652 engine.collectGarbage();
2653 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2655 QVERIFY(source.value == 0);
2658 class QListQObjectMethodsObject : public QObject
2662 QListQObjectMethodsObject() {
2663 m_objects.append(new MyQmlObject());
2664 m_objects.append(new MyQmlObject());
2667 ~QListQObjectMethodsObject() {
2668 qDeleteAll(m_objects);
2672 QList<QObject *> getObjects() { return m_objects; }
2675 QList<QObject *> m_objects;
2678 // Tests that returning a QList<QObject*> from a method works
2679 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2681 QListQObjectMethodsObject obj;
2682 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2683 context->setContextObject(&obj);
2685 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2687 QObject *object = component.create(context);
2689 QCOMPARE(object->property("test").toInt(), 2);
2690 QCOMPARE(object->property("test2").toBool(), true);
2697 void tst_qdeclarativeecmascript::strictlyEquals()
2699 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2701 QObject *object = component.create();
2702 QVERIFY(object != 0);
2704 QCOMPARE(object->property("test1").toBool(), true);
2705 QCOMPARE(object->property("test2").toBool(), true);
2706 QCOMPARE(object->property("test3").toBool(), true);
2707 QCOMPARE(object->property("test4").toBool(), true);
2708 QCOMPARE(object->property("test5").toBool(), true);
2709 QCOMPARE(object->property("test6").toBool(), true);
2710 QCOMPARE(object->property("test7").toBool(), true);
2711 QCOMPARE(object->property("test8").toBool(), true);
2716 void tst_qdeclarativeecmascript::compiled()
2718 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2720 QObject *object = component.create();
2721 QVERIFY(object != 0);
2723 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2724 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2725 QCOMPARE(object->property("test3").toBool(), true);
2726 QCOMPARE(object->property("test4").toBool(), false);
2727 QCOMPARE(object->property("test5").toBool(), false);
2728 QCOMPARE(object->property("test6").toBool(), true);
2730 QCOMPARE(object->property("test7").toInt(), 185);
2731 QCOMPARE(object->property("test8").toInt(), 167);
2732 QCOMPARE(object->property("test9").toBool(), true);
2733 QCOMPARE(object->property("test10").toBool(), false);
2734 QCOMPARE(object->property("test11").toBool(), false);
2735 QCOMPARE(object->property("test12").toBool(), true);
2737 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2738 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2739 QCOMPARE(object->property("test15").toBool(), false);
2740 QCOMPARE(object->property("test16").toBool(), true);
2742 QCOMPARE(object->property("test17").toInt(), 5);
2743 QCOMPARE(object->property("test18").toReal(), qreal(176));
2744 QCOMPARE(object->property("test19").toInt(), 7);
2745 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2746 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2747 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2748 QCOMPARE(object->property("test23").toBool(), true);
2749 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2750 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2755 // Test that numbers assigned in bindings as strings work consistently
2756 void tst_qdeclarativeecmascript::numberAssignment()
2758 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2760 QObject *object = component.create();
2761 QVERIFY(object != 0);
2763 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2764 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2765 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2766 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2767 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2769 QCOMPARE(object->property("test5"), QVariant((int)7));
2770 QCOMPARE(object->property("test6"), QVariant((int)7));
2771 QCOMPARE(object->property("test7"), QVariant((int)6));
2772 QCOMPARE(object->property("test8"), QVariant((int)6));
2774 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2775 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2776 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2777 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2782 void tst_qdeclarativeecmascript::propertySplicing()
2784 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2786 QObject *object = component.create();
2787 QVERIFY(object != 0);
2789 QCOMPARE(object->property("test").toBool(), true);
2795 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2797 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2799 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2800 QVERIFY(object != 0);
2802 MyQmlObject::MyType type;
2803 type.value = 0x8971123;
2804 emit object->signalWithUnknownType(type);
2806 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2808 QCOMPARE(result.value, type.value);
2814 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2816 QTest::addColumn<QString>("expression");
2817 QTest::addColumn<QString>("compare");
2819 QString compareStrict("(function(a, b) { return a === b; })");
2820 QTest::newRow("true") << "true" << compareStrict;
2821 QTest::newRow("undefined") << "undefined" << compareStrict;
2822 QTest::newRow("null") << "null" << compareStrict;
2823 QTest::newRow("123") << "123" << compareStrict;
2824 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2826 QString comparePropertiesStrict(
2828 " if (typeof b != 'object')"
2830 " var props = Object.getOwnPropertyNames(b);"
2831 " for (var i = 0; i < props.length; ++i) {"
2832 " var p = props[i];"
2833 " return arguments.callee(a[p], b[p]);"
2836 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2837 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2840 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2842 QFETCH(QString, expression);
2843 QFETCH(QString, compare);
2845 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2846 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2847 QVERIFY(object != 0);
2849 QJSValue value = engine.evaluate(expression);
2850 QVERIFY(!engine.hasUncaughtException());
2851 object->setProperty("expression", expression);
2852 object->setProperty("compare", compare);
2853 object->setProperty("pass", false);
2855 emit object->signalWithVariant(QVariant::fromValue(value));
2856 QVERIFY(object->property("pass").toBool());
2859 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2861 signalWithJSValueInVariant_data();
2864 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2866 QFETCH(QString, expression);
2867 QFETCH(QString, compare);
2869 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2870 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2871 QVERIFY(object != 0);
2874 QJSValue value = engine2.evaluate(expression);
2875 QVERIFY(!engine2.hasUncaughtException());
2876 object->setProperty("expression", expression);
2877 object->setProperty("compare", compare);
2878 object->setProperty("pass", false);
2880 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2881 emit object->signalWithVariant(QVariant::fromValue(value));
2882 QVERIFY(!object->property("pass").toBool());
2885 void tst_qdeclarativeecmascript::moduleApi_data()
2887 QTest::addColumn<QUrl>("testfile");
2888 QTest::addColumn<QString>("errorMessage");
2889 QTest::addColumn<QStringList>("warningMessages");
2890 QTest::addColumn<QStringList>("readProperties");
2891 QTest::addColumn<QVariantList>("readExpectedValues");
2892 QTest::addColumn<QStringList>("writeProperties");
2893 QTest::addColumn<QVariantList>("writeValues");
2894 QTest::addColumn<QStringList>("readBackProperties");
2895 QTest::addColumn<QVariantList>("readBackExpectedValues");
2897 QTest::newRow("qobject, register + read + method")
2898 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2901 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2902 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2903 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2909 QTest::newRow("script, register + read")
2910 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2913 << (QStringList() << "scriptTest")
2914 << (QVariantList() << 13)
2920 QTest::newRow("qobject, caching + read")
2921 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2924 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2925 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2931 QTest::newRow("script, caching + read")
2932 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2935 << (QStringList() << "scriptTest")
2936 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2942 QTest::newRow("qobject, writing + readonly constraints")
2943 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2945 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2946 << (QStringList() << "readOnlyProperty" << "writableProperty")
2947 << (QVariantList() << 20 << 50)
2948 << (QStringList() << "firstProperty" << "writableProperty")
2949 << (QVariantList() << 30 << 30)
2950 << (QStringList() << "readOnlyProperty" << "writableProperty")
2951 << (QVariantList() << 20 << 30);
2953 QTest::newRow("script, writing + readonly constraints")
2954 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2956 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2957 << (QStringList() << "readBack" << "unchanged")
2958 << (QVariantList() << 13 << 42)
2959 << (QStringList() << "firstProperty" << "secondProperty")
2960 << (QVariantList() << 30 << 30)
2961 << (QStringList() << "readBack" << "unchanged")
2962 << (QVariantList() << 30 << 42);
2964 QTest::newRow("qobject module API enum values in JS")
2965 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2968 << (QStringList() << "enumValue" << "enumMethod")
2969 << (QVariantList() << 42 << 30)
2975 QTest::newRow("qobject, invalid major version fail")
2976 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2977 << QString("QDeclarativeComponent: Component is not ready")
2986 QTest::newRow("qobject, invalid minor version fail")
2987 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2988 << QString("QDeclarativeComponent: Component is not ready")
2998 void tst_qdeclarativeecmascript::moduleApi()
3000 QFETCH(QUrl, testfile);
3001 QFETCH(QString, errorMessage);
3002 QFETCH(QStringList, warningMessages);
3003 QFETCH(QStringList, readProperties);
3004 QFETCH(QVariantList, readExpectedValues);
3005 QFETCH(QStringList, writeProperties);
3006 QFETCH(QVariantList, writeValues);
3007 QFETCH(QStringList, readBackProperties);
3008 QFETCH(QVariantList, readBackExpectedValues);
3010 QDeclarativeComponent component(&engine, testfile);
3012 if (!errorMessage.isEmpty())
3013 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3015 if (warningMessages.size())
3016 foreach (const QString &warning, warningMessages)
3017 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3019 QObject *object = component.create();
3020 if (!errorMessage.isEmpty()) {
3021 QVERIFY(object == 0);
3023 QVERIFY(object != 0);
3024 for (int i = 0; i < readProperties.size(); ++i)
3025 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3026 for (int i = 0; i < writeProperties.size(); ++i)
3027 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3028 for (int i = 0; i < readBackProperties.size(); ++i)
3029 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3034 void tst_qdeclarativeecmascript::importScripts_data()
3036 QTest::addColumn<QUrl>("testfile");
3037 QTest::addColumn<QString>("errorMessage");
3038 QTest::addColumn<QStringList>("warningMessages");
3039 QTest::addColumn<QStringList>("propertyNames");
3040 QTest::addColumn<QVariantList>("propertyValues");
3042 QTest::newRow("basic functionality")
3043 << TEST_FILE("jsimport/testImport.qml")
3046 << (QStringList() << QLatin1String("importedScriptStringValue")
3047 << QLatin1String("importedScriptFunctionValue")
3048 << QLatin1String("importedModuleAttachedPropertyValue")
3049 << QLatin1String("importedModuleEnumValue"))
3050 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3055 QTest::newRow("import scoping")
3056 << TEST_FILE("jsimport/testImportScoping.qml")
3059 << (QStringList() << QLatin1String("componentError"))
3060 << (QVariantList() << QVariant(5));
3062 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3063 << TEST_FILE("jsimportfail/failOne.qml")
3065 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3066 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3067 << (QVariantList() << QVariant(QString()));
3069 QTest::newRow("javascript imports in an import should be private to the import scope")
3070 << TEST_FILE("jsimportfail/failTwo.qml")
3072 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3073 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3074 << (QVariantList() << QVariant(QString()));
3076 QTest::newRow("module imports in an import should be private to the import scope")
3077 << TEST_FILE("jsimportfail/failThree.qml")
3079 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3080 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3081 << (QVariantList() << QVariant(false));
3083 QTest::newRow("typenames in an import should be private to the import scope")
3084 << TEST_FILE("jsimportfail/failFour.qml")
3086 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3087 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3088 << (QVariantList() << QVariant(0));
3090 QTest::newRow("import with imports has it's own activation scope")
3091 << TEST_FILE("jsimportfail/failFive.qml")
3093 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3094 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3095 << (QStringList() << QLatin1String("componentError"))
3096 << (QVariantList() << QVariant(0));
3098 QTest::newRow("import pragma library script")
3099 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3102 << (QStringList() << QLatin1String("testValue"))
3103 << (QVariantList() << QVariant(31));
3105 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3106 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3109 << (QStringList() << QLatin1String("testValue"))
3110 << (QVariantList() << QVariant(0));
3112 QTest::newRow("import pragma library script which has an import")
3113 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3116 << (QStringList() << QLatin1String("testValue"))
3117 << (QVariantList() << QVariant(55));
3119 QTest::newRow("import pragma library script which has a pragma library import")
3120 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3123 << (QStringList() << QLatin1String("testValue"))
3124 << (QVariantList() << QVariant(18));
3127 void tst_qdeclarativeecmascript::importScripts()
3129 QFETCH(QUrl, testfile);
3130 QFETCH(QString, errorMessage);
3131 QFETCH(QStringList, warningMessages);
3132 QFETCH(QStringList, propertyNames);
3133 QFETCH(QVariantList, propertyValues);
3135 QDeclarativeComponent component(&engine, testfile);
3137 if (!errorMessage.isEmpty())
3138 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3140 if (warningMessages.size())
3141 foreach (const QString &warning, warningMessages)
3142 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3144 QObject *object = component.create();
3145 if (!errorMessage.isEmpty()) {
3146 QVERIFY(object == 0);
3148 QVERIFY(object != 0);
3149 for (int i = 0; i < propertyNames.size(); ++i)
3150 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3155 void tst_qdeclarativeecmascript::scarceResources()
3157 QPixmap origPixmap(100, 100);
3158 origPixmap.fill(Qt::blue);
3160 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3161 ScarceResourceObject *eo = 0;
3162 QObject *object = 0;
3164 // in the following three cases, the instance created from the component
3165 // has a property which is a copy of the scarce resource; hence, the
3166 // resource should NOT be detached prior to deletion of the object instance,
3167 // unless the resource is destroyed explicitly.
3168 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3169 object = component.create();
3170 QVERIFY(object != 0);
3171 QVERIFY(object->property("scarceResourceCopy").isValid());
3172 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3173 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3174 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3175 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3178 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3179 object = componentTwo.create();
3180 QVERIFY(object != 0);
3181 QVERIFY(object->property("scarceResourceCopy").isValid());
3182 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3183 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3184 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3185 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3188 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3189 object = componentThree.create();
3190 QVERIFY(object != 0);
3191 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3192 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3193 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3194 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3197 // in the following three cases, no other copy should exist in memory,
3198 // and so it should be detached (unless explicitly preserved).
3199 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3200 object = componentFour.create();
3201 QVERIFY(object != 0);
3202 QVERIFY(object->property("scarceResourceTest").isValid());
3203 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3204 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3205 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3206 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3209 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3210 object = componentFive.create();
3211 QVERIFY(object != 0);
3212 QVERIFY(object->property("scarceResourceTest").isValid());
3213 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3214 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3215 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3216 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3219 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3220 object = componentSix.create();
3221 QVERIFY(object != 0);
3222 QVERIFY(object->property("scarceResourceTest").isValid());
3223 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3224 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3225 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3226 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3229 // test that scarce resources are handled correctly for imports
3230 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3231 object = componentSeven.create();
3232 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3233 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3236 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3237 object = componentEight.create();
3238 QVERIFY(object != 0);
3239 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3240 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3243 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3244 object = componentNine.create();
3245 QVERIFY(object != 0);
3246 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3247 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3248 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3249 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3250 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3251 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3254 // test that scarce resources are handled properly in signal invocation
3255 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3256 object = componentTen.create();
3257 QVERIFY(object != 0);
3258 QObject *srsc = object->findChild<QObject*>("srsc");
3260 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3261 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3262 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3263 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3264 QMetaObject::invokeMethod(srsc, "testSignal");
3265 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3266 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3267 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3268 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3269 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3270 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3271 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3272 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3273 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3274 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3277 // test that scarce resources are handled properly from js functions in qml files
3278 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3279 object = componentEleven.create();
3280 QVERIFY(object != 0);
3281 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3282 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3283 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3284 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3285 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3286 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3287 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3288 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3289 QMetaObject::invokeMethod(object, "releaseScarceResource");
3290 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3291 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3292 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3293 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3296 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3297 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3298 object = componentTwelve.create();
3299 QVERIFY(object != 0);
3300 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3301 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3302 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3303 QString srp_name = object->property("srp_name").toString();
3304 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3305 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3306 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3307 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3308 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3309 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3310 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3314 void tst_qdeclarativeecmascript::propertyChangeSlots()
3316 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3317 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3318 QObject *object = component.create();
3319 QVERIFY(object != 0);
3322 // ensure that invalid property names fail properly.
3323 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3324 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3325 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3326 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3327 object = e1.create();
3328 QVERIFY(object == 0);
3331 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3332 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3333 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3334 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3335 object = e2.create();
3336 QVERIFY(object == 0);
3339 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3340 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3341 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3342 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3343 object = e3.create();
3344 QVERIFY(object == 0);
3347 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3348 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3349 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3350 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3351 object = e4.create();
3352 QVERIFY(object == 0);
3356 void tst_qdeclarativeecmascript::propertyVar_data()
3358 QTest::addColumn<QUrl>("qmlFile");
3361 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3362 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3363 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3364 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3365 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3366 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3367 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3368 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3369 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3372 void tst_qdeclarativeecmascript::propertyVar()
3374 QFETCH(QUrl, qmlFile);
3376 QDeclarativeComponent component(&engine, qmlFile);
3377 QObject *object = component.create();
3378 QVERIFY(object != 0);
3380 QCOMPARE(object->property("test").toBool(), true);
3385 // Tests that we can write QVariant values to var properties from C++
3386 void tst_qdeclarativeecmascript::propertyVarCpp()
3388 QObject *object = 0;
3390 // ensure that writing to and reading from a var property from cpp works as required.
3391 // Literal values stored in var properties can be read and written as QVariants
3392 // of a specific type, whereas object values are read as QVariantMaps.
3393 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3394 object = component.create();
3395 QVERIFY(object != 0);
3396 // assign int to property var that currently has int assigned
3397 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3398 QCOMPARE(object->property("varBound"), QVariant(15));
3399 QCOMPARE(object->property("intBound"), QVariant(15));
3400 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3401 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3402 // assign string to property var that current has bool assigned
3403 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3404 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3405 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3406 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3407 // now enforce behaviour when accessing JavaScript objects from cpp.
3408 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3412 static void gc(QDeclarativeEngine &engine)
3414 engine.collectGarbage();
3415 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3418 void tst_qdeclarativeecmascript::propertyVarOwnership()
3420 // Referenced JS objects are not collected
3422 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3423 QObject *object = component.create();
3424 QVERIFY(object != 0);
3425 QCOMPARE(object->property("test").toBool(), false);
3426 QMetaObject::invokeMethod(object, "runTest");
3427 QCOMPARE(object->property("test").toBool(), true);
3430 // Referenced JS objects are not collected
3432 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3433 QObject *object = component.create();
3434 QVERIFY(object != 0);
3435 QCOMPARE(object->property("test").toBool(), false);
3436 QMetaObject::invokeMethod(object, "runTest");
3437 QCOMPARE(object->property("test").toBool(), true);
3440 // Qt objects are not collected until they've been dereferenced
3442 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3443 QObject *object = component.create();
3444 QVERIFY(object != 0);
3446 QCOMPARE(object->property("test2").toBool(), false);
3447 QCOMPARE(object->property("test2").toBool(), false);
3449 QMetaObject::invokeMethod(object, "runTest");
3450 QCOMPARE(object->property("test1").toBool(), true);
3452 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3453 QVERIFY(!referencedObject.isNull());
3455 QVERIFY(!referencedObject.isNull());
3457 QMetaObject::invokeMethod(object, "runTest2");
3458 QCOMPARE(object->property("test2").toBool(), true);
3460 QVERIFY(referencedObject.isNull());
3464 // Self reference does not prevent Qt object collection
3466 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3467 QObject *object = component.create();
3468 QVERIFY(object != 0);
3470 QCOMPARE(object->property("test").toBool(), true);
3472 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3473 QVERIFY(!referencedObject.isNull());
3475 QVERIFY(!referencedObject.isNull());
3477 QMetaObject::invokeMethod(object, "runTest");
3479 QVERIFY(referencedObject.isNull());
3485 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3487 // The childObject has a reference to a different QObject. We want to ensure
3488 // that the different item will not be cleaned up until required. IE, the childObject
3489 // has implicit ownership of the constructed QObject.
3490 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3491 QObject *object = component.create();
3492 QVERIFY(object != 0);
3493 QMetaObject::invokeMethod(object, "assignCircular");
3494 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3495 QObject *rootObject = object->property("vp").value<QObject*>();
3496 QVERIFY(rootObject != 0);
3497 QObject *childObject = rootObject->findChild<QObject*>("text");
3498 QVERIFY(childObject != 0);
3499 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3500 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3501 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3502 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3503 QVERIFY(!qobjectGuard.isNull());
3504 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3505 QVERIFY(!qobjectGuard.isNull());
3506 QMetaObject::invokeMethod(object, "deassignCircular");
3507 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3508 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3512 void tst_qdeclarativeecmascript::propertyVarReparent()
3514 // ensure that nothing breaks if we re-parent objects
3515 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3516 QObject *object = component.create();
3517 QVERIFY(object != 0);
3518 QMetaObject::invokeMethod(object, "assignVarProp");
3519 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3520 QObject *rect = object->property("vp").value<QObject*>();
3521 QObject *text = rect->findChild<QObject*>("textOne");
3522 QObject *text2 = rect->findChild<QObject*>("textTwo");
3523 QWeakPointer<QObject> rectGuard(rect);
3524 QWeakPointer<QObject> textGuard(text);
3525 QWeakPointer<QObject> text2Guard(text2);
3526 QVERIFY(!rectGuard.isNull());
3527 QVERIFY(!textGuard.isNull());
3528 QVERIFY(!text2Guard.isNull());
3529 QCOMPARE(text->property("textCanary").toInt(), 11);
3530 QCOMPARE(text2->property("textCanary").toInt(), 12);
3531 // now construct an image which we will reparent.
3532 QMetaObject::invokeMethod(text2, "constructQObject");
3533 QObject *image = text2->property("vp").value<QObject*>();
3534 QWeakPointer<QObject> imageGuard(image);
3535 QVERIFY(!imageGuard.isNull());
3536 QCOMPARE(image->property("imageCanary").toInt(), 13);
3537 // now reparent the "Image" object (currently, it has JS ownership)
3538 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3539 QMetaObject::invokeMethod(text2, "deassignVp");
3540 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3541 QCOMPARE(text->property("textCanary").toInt(), 11);
3542 QCOMPARE(text2->property("textCanary").toInt(), 22);
3543 QVERIFY(!imageGuard.isNull()); // should still be alive.
3544 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3545 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3546 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3547 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3551 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3553 // sometimes reparenting can cause problems
3554 // (eg, if the ctxt is collected, varproperties are no longer available)
3555 // this test ensures that no crash occurs in that situation.
3556 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3557 QObject *object = component.create();
3558 QVERIFY(object != 0);
3559 QMetaObject::invokeMethod(object, "assignVarProp");
3560 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3561 QObject *rect = object->property("vp").value<QObject*>();
3562 QObject *text = rect->findChild<QObject*>("textOne");
3563 QObject *text2 = rect->findChild<QObject*>("textTwo");
3564 QWeakPointer<QObject> rectGuard(rect);
3565 QWeakPointer<QObject> textGuard(text);
3566 QWeakPointer<QObject> text2Guard(text2);
3567 QVERIFY(!rectGuard.isNull());
3568 QVERIFY(!textGuard.isNull());
3569 QVERIFY(!text2Guard.isNull());
3570 QCOMPARE(text->property("textCanary").toInt(), 11);
3571 QCOMPARE(text2->property("textCanary").toInt(), 12);
3572 // now construct an image which we will reparent.
3573 QMetaObject::invokeMethod(text2, "constructQObject");
3574 QObject *image = text2->property("vp").value<QObject*>();
3575 QWeakPointer<QObject> imageGuard(image);
3576 QVERIFY(!imageGuard.isNull());
3577 QCOMPARE(image->property("imageCanary").toInt(), 13);
3578 // now reparent the "Image" object (currently, it has JS ownership)
3579 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3580 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3581 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3582 QVERIFY(!imageGuard.isNull()); // should still be alive.
3583 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3585 QVERIFY(imageGuard.isNull()); // should now be dead.
3588 void tst_qdeclarativeecmascript::propertyVarCircular()
3590 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3591 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3592 QObject *object = component.create();
3593 QVERIFY(object != 0);
3594 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3595 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3596 QCOMPARE(object->property("canaryInt"), QVariant(5));
3597 QVariant canaryResourceVariant = object->property("canaryResource");
3598 QVERIFY(canaryResourceVariant.isValid());
3599 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3600 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3601 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3602 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3603 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3604 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3605 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3606 QCOMPARE(object->property("canaryInt"), QVariant(2));
3607 QCOMPARE(object->property("canaryResource"), QVariant(1));
3608 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3612 void tst_qdeclarativeecmascript::propertyVarCircular2()
3614 // track deletion of JS-owned parent item with Cpp-owned child
3615 // where the child has a var property referencing its parent.
3616 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3617 QObject *object = component.create();
3618 QVERIFY(object != 0);
3619 QMetaObject::invokeMethod(object, "assignCircular");
3620 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3621 QObject *rootObject = object->property("vp").value<QObject*>();
3622 QVERIFY(rootObject != 0);
3623 QObject *childObject = rootObject->findChild<QObject*>("text");
3624 QVERIFY(childObject != 0);
3625 QWeakPointer<QObject> rootObjectTracker(rootObject);
3626 QVERIFY(!rootObjectTracker.isNull());
3627 QWeakPointer<QObject> childObjectTracker(childObject);
3628 QVERIFY(!childObjectTracker.isNull());
3630 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3631 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3632 QMetaObject::invokeMethod(object, "deassignCircular");
3633 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3634 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3635 QVERIFY(childObjectTracker.isNull()); // should have been collected
3639 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3641 *(int*)(parameter) += 1;
3642 qPersistentDispose(object);
3645 void tst_qdeclarativeecmascript::propertyVarInheritance()
3647 int propertyVarWeakRefCallbackCount = 0;
3649 // enforce behaviour regarding element inheritance - ensure handle disposal.
3650 // The particular component under test here has a chain of references.
3651 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3652 QObject *object = component.create();
3653 QVERIFY(object != 0);
3654 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3655 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3656 // we want to be able to track when the varProperties array of the last metaobject is disposed
3657 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3658 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*>();
3659 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3660 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3661 v8::Persistent<v8::Value> icoCanaryHandle;
3662 v8::Persistent<v8::Value> ccoCanaryHandle;
3665 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3666 // public function which can return us a handle to something in the varProperties array.
3667 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3668 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3669 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3670 // as the varproperties array of each vmemo still references the resource.
3671 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3672 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3674 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3676 // now we deassign the var prop, which should trigger collection of item subtrees.
3677 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3678 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3679 // ensure that there are only weak handles to the underlying varProperties array remaining.
3681 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3683 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3684 // to what remains are weak, all varProperties arrays must have been collected.
3687 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3689 int propertyVarWeakRefCallbackCount = 0;
3691 // The particular component under test here does NOT have a chain of references; the
3692 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3693 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3694 QObject *object = component.create();
3695 QVERIFY(object != 0);
3696 QMetaObject::invokeMethod(object, "assignCircular");
3697 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3698 QObject *rootObject = object->property("vp").value<QObject*>();
3699 QVERIFY(rootObject != 0);
3700 QObject *childObject = rootObject->findChild<QObject*>("text");
3701 QVERIFY(childObject != 0);
3702 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3703 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3704 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3707 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3708 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3709 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3711 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3712 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3714 QMetaObject::invokeMethod(object, "deassignCircular");
3715 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3716 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3720 // Ensure that QObject type conversion works on binding assignment
3721 void tst_qdeclarativeecmascript::elementAssign()
3723 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3725 QObject *object = component.create();
3726 QVERIFY(object != 0);
3728 QCOMPARE(object->property("test").toBool(), true);
3734 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3736 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3738 QObject *object = component.create();
3739 QVERIFY(object != 0);
3741 QCOMPARE(object->property("test").toBool(), true);
3747 void tst_qdeclarativeecmascript::objectConversion()
3749 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3751 QObject *object = component.create();
3752 QVERIFY(object != 0);
3754 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3755 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3762 void tst_qdeclarativeecmascript::booleanConversion()
3764 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3766 QObject *object = component.create();
3767 QVERIFY(object != 0);
3769 QCOMPARE(object->property("test_true1").toBool(), true);
3770 QCOMPARE(object->property("test_true2").toBool(), true);
3771 QCOMPARE(object->property("test_true3").toBool(), true);
3772 QCOMPARE(object->property("test_true4").toBool(), true);
3773 QCOMPARE(object->property("test_true5").toBool(), true);
3775 QCOMPARE(object->property("test_false1").toBool(), false);
3776 QCOMPARE(object->property("test_false2").toBool(), false);
3777 QCOMPARE(object->property("test_false3").toBool(), false);
3782 void tst_qdeclarativeecmascript::handleReferenceManagement()
3787 // Linear QObject reference
3788 QDeclarativeEngine hrmEngine;
3789 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3790 QObject *object = component.create();
3791 QVERIFY(object != 0);
3792 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3793 cro->setDtorCount(&dtorCount);
3794 QMetaObject::invokeMethod(object, "createReference");
3796 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3798 hrmEngine.collectGarbage();
3799 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3800 QCOMPARE(dtorCount, 3);
3805 // Circular QObject reference
3806 QDeclarativeEngine hrmEngine;
3807 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3808 QObject *object = component.create();
3809 QVERIFY(object != 0);
3810 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3811 cro->setDtorCount(&dtorCount);
3812 QMetaObject::invokeMethod(object, "circularReference");
3814 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3816 hrmEngine.collectGarbage();
3817 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3818 QCOMPARE(dtorCount, 3);
3823 // Linear handle reference
3824 QDeclarativeEngine hrmEngine;
3825 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3826 QObject *object = component.create();
3827 QVERIFY(object != 0);
3828 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3830 crh->setDtorCount(&dtorCount);
3831 QMetaObject::invokeMethod(object, "createReference");
3832 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3833 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3834 QVERIFY(first != 0);
3835 QVERIFY(second != 0);
3836 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3837 // now we have to reparent second and make second owned by JS.
3838 second->setParent(0);
3839 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3841 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3843 hrmEngine.collectGarbage();
3844 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3845 QCOMPARE(dtorCount, 3);
3850 // Circular handle reference
3851 QDeclarativeEngine hrmEngine;
3852 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3853 QObject *object = component.create();
3854 QVERIFY(object != 0);
3855 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3857 crh->setDtorCount(&dtorCount);
3858 QMetaObject::invokeMethod(object, "circularReference");
3859 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3860 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3861 QVERIFY(first != 0);
3862 QVERIFY(second != 0);
3863 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3864 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3865 // now we have to reparent and change ownership.
3866 first->setParent(0);
3867 second->setParent(0);
3868 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3869 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3871 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3873 hrmEngine.collectGarbage();
3874 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3875 QCOMPARE(dtorCount, 3);
3880 // multiple engine interaction - linear reference
3881 QDeclarativeEngine hrmEngine1;
3882 QDeclarativeEngine hrmEngine2;
3883 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3884 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3885 QObject *object1 = component1.create();
3886 QObject *object2 = component2.create();
3887 QVERIFY(object1 != 0);
3888 QVERIFY(object2 != 0);
3889 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3890 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3893 crh1->setDtorCount(&dtorCount);
3894 crh2->setDtorCount(&dtorCount);
3895 QMetaObject::invokeMethod(object1, "createReference");
3896 QMetaObject::invokeMethod(object2, "createReference");
3897 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3898 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3899 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3900 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3901 QVERIFY(first1 != 0);
3902 QVERIFY(second1 != 0);
3903 QVERIFY(first2 != 0);
3904 QVERIFY(second2 != 0);
3905 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3906 // now we have to reparent second2 and make second2 owned by JS.
3907 second2->setParent(0);
3908 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3910 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3911 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3914 hrmEngine1.collectGarbage();
3915 hrmEngine2.collectGarbage();
3916 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3917 QCOMPARE(dtorCount, 6);
3922 // multiple engine interaction - circular reference
3923 QDeclarativeEngine hrmEngine1;
3924 QDeclarativeEngine hrmEngine2;
3925 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3926 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3927 QObject *object1 = component1.create();
3928 QObject *object2 = component2.create();
3929 QVERIFY(object1 != 0);
3930 QVERIFY(object2 != 0);
3931 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3932 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3935 crh1->setDtorCount(&dtorCount);
3936 crh2->setDtorCount(&dtorCount);
3937 QMetaObject::invokeMethod(object1, "createReference");
3938 QMetaObject::invokeMethod(object2, "createReference");
3939 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3940 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3941 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3942 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3943 QVERIFY(first1 != 0);
3944 QVERIFY(second1 != 0);
3945 QVERIFY(first2 != 0);
3946 QVERIFY(second2 != 0);
3947 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3948 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3949 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3950 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3951 // now we have to reparent and change ownership to JS.
3952 first1->setParent(0);
3953 second1->setParent(0);
3954 first2->setParent(0);
3955 second2->setParent(0);
3956 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3957 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3958 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3959 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3961 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3962 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3965 hrmEngine1.collectGarbage();
3966 hrmEngine2.collectGarbage();
3967 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3968 QCOMPARE(dtorCount, 6);
3973 // multiple engine interaction - linear reference with engine deletion
3974 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3975 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3976 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3977 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3978 QObject *object1 = component1.create();
3979 QObject *object2 = component2.create();
3980 QVERIFY(object1 != 0);
3981 QVERIFY(object2 != 0);
3982 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3983 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3986 crh1->setDtorCount(&dtorCount);
3987 crh2->setDtorCount(&dtorCount);
3988 QMetaObject::invokeMethod(object1, "createReference");
3989 QMetaObject::invokeMethod(object2, "createReference");
3990 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3991 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3992 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3993 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3994 QVERIFY(first1 != 0);
3995 QVERIFY(second1 != 0);
3996 QVERIFY(first2 != 0);
3997 QVERIFY(second2 != 0);
3998 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3999 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4000 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4001 // now we have to reparent and change ownership to JS.
4002 first1->setParent(crh1);
4003 second1->setParent(0);
4004 first2->setParent(0);
4005 second2->setParent(0);
4006 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4007 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4008 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4010 QCOMPARE(dtorCount, 0);
4013 QCOMPARE(dtorCount, 0);
4016 hrmEngine1->collectGarbage();
4017 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4018 QCOMPARE(dtorCount, 6);
4023 void tst_qdeclarativeecmascript::stringArg()
4025 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4026 QObject *object = component.create();
4027 QVERIFY(object != 0);
4028 QMetaObject::invokeMethod(object, "success");
4029 QVERIFY(object->property("returnValue").toBool());
4031 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4032 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4033 QMetaObject::invokeMethod(object, "failure");
4034 QVERIFY(object->property("returnValue").toBool());
4039 // Test that assigning a null object works
4040 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4041 void tst_qdeclarativeecmascript::nullObjectBinding()
4043 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4045 QObject *object = component.create();
4046 QVERIFY(object != 0);
4048 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4053 // Test that bindings don't evaluate once the engine has been destroyed
4054 void tst_qdeclarativeecmascript::deletedEngine()
4056 QDeclarativeEngine *engine = new QDeclarativeEngine;
4057 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4059 QObject *object = component.create();
4060 QVERIFY(object != 0);
4062 QCOMPARE(object->property("a").toInt(), 39);
4063 object->setProperty("b", QVariant(9));
4064 QCOMPARE(object->property("a").toInt(), 117);
4068 QCOMPARE(object->property("a").toInt(), 117);
4069 object->setProperty("b", QVariant(10));
4070 QCOMPARE(object->property("a").toInt(), 117);
4075 // Test the crashing part of QTBUG-9705
4076 void tst_qdeclarativeecmascript::libraryScriptAssert()
4078 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4080 QObject *object = component.create();
4081 QVERIFY(object != 0);
4086 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4088 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4090 QObject *object = component.create();
4091 QVERIFY(object != 0);
4093 QCOMPARE(object->property("test1").toInt(), 10);
4094 QCOMPARE(object->property("test2").toInt(), 11);
4096 object->setProperty("runTest", true);
4098 QCOMPARE(object->property("test1"), QVariant());
4099 QCOMPARE(object->property("test2"), QVariant());
4105 void tst_qdeclarativeecmascript::qtbug_9792()
4107 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4109 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4111 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4112 QVERIFY(object != 0);
4114 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4115 object->basicSignal();
4119 transientErrorsMsgCount = 0;
4120 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4122 object->basicSignal();
4124 qInstallMsgHandler(old);
4126 QCOMPARE(transientErrorsMsgCount, 0);
4131 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4132 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4134 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4136 QObject *o = component.create();
4139 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4140 QVERIFY(nested != 0);
4142 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4145 nested = qvariant_cast<QObject *>(o->property("object"));
4146 QVERIFY(nested == 0);
4148 // If the bug is present, the next line will crash
4152 // Test that we shut down without stupid warnings
4153 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4156 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4158 QObject *o = component.create();
4160 transientErrorsMsgCount = 0;
4161 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4165 qInstallMsgHandler(old);
4167 QCOMPARE(transientErrorsMsgCount, 0);
4172 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4174 QObject *o = component.create();
4176 transientErrorsMsgCount = 0;
4177 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4181 qInstallMsgHandler(old);
4183 QCOMPARE(transientErrorsMsgCount, 0);
4187 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4190 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4192 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4195 QVERIFY(o->objectProperty() != 0);
4197 o->setProperty("runTest", true);
4199 QVERIFY(o->objectProperty() == 0);
4205 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4207 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4210 QVERIFY(o->objectProperty() == 0);
4216 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4218 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4220 QString url = component.url().toString();
4221 QString warning = url + ":4: Unable to assign a function to a property.";
4222 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4224 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4227 QVERIFY(!o->property("a").isValid());
4232 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4234 QFETCH(QString, triggerProperty);
4236 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4237 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4239 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4241 QVERIFY(!o->property("a").isValid());
4243 o->setProperty("aNumber", QVariant(5));
4244 o->setProperty(triggerProperty.toUtf8().constData(), true);
4245 QCOMPARE(o->property("a"), QVariant(50));
4247 o->setProperty("aNumber", QVariant(10));
4248 QCOMPARE(o->property("a"), QVariant(100));
4253 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4255 QTest::addColumn<QString>("triggerProperty");
4257 QTest::newRow("assign to property") << "assignToProperty";
4258 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4260 QTest::newRow("assign to value type") << "assignToValueType";
4262 QTest::newRow("use 'this'") << "assignWithThis";
4263 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4266 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4268 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4269 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4271 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4273 QVERIFY(!o->property("a").isValid());
4275 o->setProperty("assignFuncWithoutReturn", true);
4276 QVERIFY(!o->property("a").isValid());
4278 QString url = component.url().toString();
4279 QString warning = url + ":67: Unable to assign QString to int";
4280 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4281 o->setProperty("assignWrongType", true);
4283 warning = url + ":71: Unable to assign QString to int";
4284 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4285 o->setProperty("assignWrongTypeToValueType", true);
4290 void tst_qdeclarativeecmascript::eval()
4292 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4294 QObject *o = component.create();
4297 QCOMPARE(o->property("test1").toBool(), true);
4298 QCOMPARE(o->property("test2").toBool(), true);
4299 QCOMPARE(o->property("test3").toBool(), true);
4300 QCOMPARE(o->property("test4").toBool(), true);
4301 QCOMPARE(o->property("test5").toBool(), true);
4306 void tst_qdeclarativeecmascript::function()
4308 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4310 QObject *o = component.create();
4313 QCOMPARE(o->property("test1").toBool(), true);
4314 QCOMPARE(o->property("test2").toBool(), true);
4315 QCOMPARE(o->property("test3").toBool(), true);
4320 // Test the "Qt.include" method
4321 void tst_qdeclarativeecmascript::include()
4323 // Non-library relative include
4325 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4326 QObject *o = component.create();
4329 QCOMPARE(o->property("test0").toInt(), 99);
4330 QCOMPARE(o->property("test1").toBool(), true);
4331 QCOMPARE(o->property("test2").toBool(), true);
4332 QCOMPARE(o->property("test2_1").toBool(), true);
4333 QCOMPARE(o->property("test3").toBool(), true);
4334 QCOMPARE(o->property("test3_1").toBool(), true);
4339 // Library relative include
4341 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4342 QObject *o = component.create();
4345 QCOMPARE(o->property("test0").toInt(), 99);
4346 QCOMPARE(o->property("test1").toBool(), true);
4347 QCOMPARE(o->property("test2").toBool(), true);
4348 QCOMPARE(o->property("test2_1").toBool(), true);
4349 QCOMPARE(o->property("test3").toBool(), true);
4350 QCOMPARE(o->property("test3_1").toBool(), true);
4357 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4358 QObject *o = component.create();
4361 QCOMPARE(o->property("test1").toBool(), true);
4362 QCOMPARE(o->property("test2").toBool(), true);
4363 QCOMPARE(o->property("test3").toBool(), true);
4364 QCOMPARE(o->property("test4").toBool(), true);
4365 QCOMPARE(o->property("test5").toBool(), true);
4366 QCOMPARE(o->property("test6").toBool(), true);
4371 // Including file with ".pragma library"
4373 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4374 QObject *o = component.create();
4376 QCOMPARE(o->property("test1").toInt(), 100);
4383 TestHTTPServer server(8111);
4384 QVERIFY(server.isValid());
4385 server.serveDirectory(TESTDATA(""));
4387 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4388 QObject *o = component.create();
4391 QTRY_VERIFY(o->property("done").toBool() == true);
4392 QTRY_VERIFY(o->property("done2").toBool() == true);
4394 QCOMPARE(o->property("test1").toBool(), true);
4395 QCOMPARE(o->property("test2").toBool(), true);
4396 QCOMPARE(o->property("test3").toBool(), true);
4397 QCOMPARE(o->property("test4").toBool(), true);
4398 QCOMPARE(o->property("test5").toBool(), true);
4400 QCOMPARE(o->property("test6").toBool(), true);
4401 QCOMPARE(o->property("test7").toBool(), true);
4402 QCOMPARE(o->property("test8").toBool(), true);
4403 QCOMPARE(o->property("test9").toBool(), true);
4404 QCOMPARE(o->property("test10").toBool(), true);
4411 TestHTTPServer server(8111);
4412 QVERIFY(server.isValid());
4413 server.serveDirectory(TESTDATA(""));
4415 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4416 QObject *o = component.create();
4419 QTRY_VERIFY(o->property("done").toBool() == true);
4421 QCOMPARE(o->property("test1").toBool(), true);
4422 QCOMPARE(o->property("test2").toBool(), true);
4423 QCOMPARE(o->property("test3").toBool(), true);
4429 void tst_qdeclarativeecmascript::signalHandlers()
4431 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4432 QObject *o = component.create();
4435 QVERIFY(o->property("count").toInt() == 0);
4436 QMetaObject::invokeMethod(o, "testSignalCall");
4437 QCOMPARE(o->property("count").toInt(), 1);
4439 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4440 QCOMPARE(o->property("count").toInt(), 1);
4441 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4443 QVERIFY(o->property("funcCount").toInt() == 0);
4444 QMetaObject::invokeMethod(o, "testSignalConnection");
4445 QCOMPARE(o->property("funcCount").toInt(), 1);
4447 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4448 QCOMPARE(o->property("funcCount").toInt(), 2);
4450 QMetaObject::invokeMethod(o, "testSignalDefined");
4451 QCOMPARE(o->property("definedResult").toBool(), true);
4453 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4454 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4459 void tst_qdeclarativeecmascript::qtbug_10696()
4461 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4462 QObject *o = component.create();
4467 void tst_qdeclarativeecmascript::qtbug_11606()
4469 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4470 QObject *o = component.create();
4472 QCOMPARE(o->property("test").toBool(), true);
4476 void tst_qdeclarativeecmascript::qtbug_11600()
4478 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4479 QObject *o = component.create();
4481 QCOMPARE(o->property("test").toBool(), true);
4485 // Reading and writing non-scriptable properties should fail
4486 void tst_qdeclarativeecmascript::nonscriptable()
4488 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4489 QObject *o = component.create();
4491 QCOMPARE(o->property("readOk").toBool(), true);
4492 QCOMPARE(o->property("writeOk").toBool(), true);
4496 // deleteLater() should not be callable from QML
4497 void tst_qdeclarativeecmascript::deleteLater()
4499 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4500 QObject *o = component.create();
4502 QCOMPARE(o->property("test").toBool(), true);
4506 void tst_qdeclarativeecmascript::in()
4508 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4509 QObject *o = component.create();
4511 QCOMPARE(o->property("test1").toBool(), true);
4512 QCOMPARE(o->property("test2").toBool(), true);
4516 void tst_qdeclarativeecmascript::typeOf()
4518 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4519 QObject *o = component.create();
4521 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4522 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4523 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4524 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4525 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4526 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4527 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4528 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4529 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4530 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4535 void tst_qdeclarativeecmascript::sharedAttachedObject()
4537 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4538 QObject *o = component.create();
4540 QCOMPARE(o->property("test1").toBool(), true);
4541 QCOMPARE(o->property("test2").toBool(), true);
4546 void tst_qdeclarativeecmascript::objectName()
4548 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4549 QObject *o = component.create();
4552 QCOMPARE(o->property("test1").toString(), QString("hello"));
4553 QCOMPARE(o->property("test2").toString(), QString("ell"));
4555 o->setObjectName("world");
4557 QCOMPARE(o->property("test1").toString(), QString("world"));
4558 QCOMPARE(o->property("test2").toString(), QString("orl"));
4563 void tst_qdeclarativeecmascript::writeRemovesBinding()
4565 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4566 QObject *o = component.create();
4569 QCOMPARE(o->property("test").toBool(), true);
4574 // Test bindings assigned to alias properties actually assign to the alias' target
4575 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4577 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4578 QObject *o = component.create();
4581 QCOMPARE(o->property("test").toBool(), true);
4586 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4587 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4590 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4591 QObject *o = component.create();
4594 QCOMPARE(o->property("test").toBool(), true);
4600 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4601 QObject *o = component.create();
4604 QCOMPARE(o->property("test").toBool(), true);
4610 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4611 QObject *o = component.create();
4614 QCOMPARE(o->property("test").toBool(), true);
4620 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4621 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4624 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4625 QObject *o = component.create();
4628 QCOMPARE(o->property("test").toBool(), true);
4634 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4635 QObject *o = component.create();
4638 QCOMPARE(o->property("test").toBool(), true);
4644 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4645 QObject *o = component.create();
4648 QCOMPARE(o->property("test").toBool(), true);
4654 // Allow an alais to a composite element
4656 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4658 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4660 QObject *object = component.create();
4661 QVERIFY(object != 0);
4666 void tst_qdeclarativeecmascript::revisionErrors()
4669 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4670 QString url = component.url().toString();
4672 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4673 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4674 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4676 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4677 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4678 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4679 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4680 QVERIFY(object != 0);
4684 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4685 QString url = component.url().toString();
4687 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4688 // method2, prop2 from MyRevisionedClass not available
4689 // method4, prop4 from MyRevisionedSubclass not available
4690 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4691 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4692 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4693 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4694 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4696 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4697 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4698 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4699 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4700 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4701 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4702 QVERIFY(object != 0);
4706 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4707 QString url = component.url().toString();
4709 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4710 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4711 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4712 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4713 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4714 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4715 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4716 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4717 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4718 QVERIFY(object != 0);
4723 void tst_qdeclarativeecmascript::revision()
4726 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4727 QString url = component.url().toString();
4729 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4730 QVERIFY(object != 0);
4734 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4735 QString url = component.url().toString();
4737 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4738 QVERIFY(object != 0);
4742 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4743 QString url = component.url().toString();
4745 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4746 QVERIFY(object != 0);
4749 // Test that non-root classes can resolve revisioned methods
4751 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4753 QObject *object = component.create();
4754 QVERIFY(object != 0);
4755 QCOMPARE(object->property("test").toReal(), 11.);
4760 void tst_qdeclarativeecmascript::realToInt()
4762 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
4763 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
4764 QVERIFY(object != 0);
4766 QMetaObject::invokeMethod(object, "test1");
4767 QCOMPARE(object->value(), int(4));
4768 QMetaObject::invokeMethod(object, "test2");
4769 QCOMPARE(object->value(), int(8));
4771 void tst_qdeclarativeecmascript::dynamicString()
4773 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
4774 QObject *object = component.create();
4775 QVERIFY(object != 0);
4776 QCOMPARE(object->property("stringProperty").toString(),
4777 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
4780 void tst_qdeclarativeecmascript::automaticSemicolon()
4782 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
4783 QObject *object = component.create();
4784 QVERIFY(object != 0);
4787 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
4788 void tst_qdeclarativeecmascript::doubleEvaluate()
4790 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
4791 QObject *object = component.create();
4792 QVERIFY(object != 0);
4793 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
4795 QCOMPARE(wc->count(), 1);
4797 wc->setProperty("x", 9);
4799 QCOMPARE(wc->count(), 2);
4804 void tst_qdeclarativeecmascript::forInLoop()
4806 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
4807 QObject *object = component.create();
4808 QVERIFY(object != 0);
4810 QMetaObject::invokeMethod(object, "listProperty");
4812 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
4813 QCOMPARE(r.size(), 3);
4814 QCOMPARE(r[0],QLatin1String("0=obj1"));
4815 QCOMPARE(r[1],QLatin1String("1=obj2"));
4816 QCOMPARE(r[2],QLatin1String("2=obj3"));
4818 //TODO: should test for in loop for other objects (such as QObjects) as well.
4823 QTEST_MAIN(tst_qdeclarativeecmascript)
4825 #include "tst_qdeclarativeecmascript.moc"