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