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();
223 void dynamicString();
225 void signalHandlers();
226 void doubleEvaluate();
228 void nonNotifyable();
229 void deleteWhileBindingRunning();
230 void callQtInvokables();
231 void invokableObjectArg();
232 void invokableObjectRet();
235 void qtbug_22843_data();
237 void revisionErrors();
240 void automaticSemicolon();
241 void unaryExpression();
242 void switchStatement();
243 void withStatement();
247 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
248 QDeclarativeEngine engine;
251 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
253 void tst_qdeclarativeecmascript::assignBasicTypes()
256 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
257 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
258 QVERIFY(object != 0);
259 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
260 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
261 QCOMPARE(object->stringProperty(), QString("Hello World!"));
262 QCOMPARE(object->uintProperty(), uint(10));
263 QCOMPARE(object->intProperty(), -19);
264 QCOMPARE((float)object->realProperty(), float(23.2));
265 QCOMPARE((float)object->doubleProperty(), float(-19.75));
266 QCOMPARE((float)object->floatProperty(), float(8.5));
267 QCOMPARE(object->colorProperty(), QColor("red"));
268 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
269 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
270 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
271 QCOMPARE(object->pointProperty(), QPoint(99,13));
272 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
273 QCOMPARE(object->sizeProperty(), QSize(99, 13));
274 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
275 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
276 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
277 QCOMPARE(object->boolProperty(), true);
278 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
279 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
280 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
284 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
285 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
286 QVERIFY(object != 0);
287 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
288 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
289 QCOMPARE(object->stringProperty(), QString("Hello World!"));
290 QCOMPARE(object->uintProperty(), uint(10));
291 QCOMPARE(object->intProperty(), -19);
292 QCOMPARE((float)object->realProperty(), float(23.2));
293 QCOMPARE((float)object->doubleProperty(), float(-19.75));
294 QCOMPARE((float)object->floatProperty(), float(8.5));
295 QCOMPARE(object->colorProperty(), QColor("red"));
296 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
297 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
298 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
299 QCOMPARE(object->pointProperty(), QPoint(99,13));
300 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
301 QCOMPARE(object->sizeProperty(), QSize(99, 13));
302 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
303 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
304 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
305 QCOMPARE(object->boolProperty(), true);
306 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
307 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
308 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
313 void tst_qdeclarativeecmascript::idShortcutInvalidates()
316 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
317 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
318 QVERIFY(object != 0);
319 QVERIFY(object->objectProperty() != 0);
320 delete object->objectProperty();
321 QVERIFY(object->objectProperty() == 0);
326 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
327 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
328 QVERIFY(object != 0);
329 QVERIFY(object->objectProperty() != 0);
330 delete object->objectProperty();
331 QVERIFY(object->objectProperty() == 0);
336 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
339 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
340 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
341 QVERIFY(object != 0);
342 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
346 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
347 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
348 QVERIFY(object != 0);
349 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
354 void tst_qdeclarativeecmascript::signalAssignment()
357 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
358 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
359 QVERIFY(object != 0);
360 QCOMPARE(object->string(), QString());
361 emit object->basicSignal();
362 QCOMPARE(object->string(), QString("pass"));
367 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
368 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
369 QVERIFY(object != 0);
370 QCOMPARE(object->string(), QString());
371 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
372 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
377 void tst_qdeclarativeecmascript::methods()
380 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
381 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
382 QVERIFY(object != 0);
383 QCOMPARE(object->methodCalled(), false);
384 QCOMPARE(object->methodIntCalled(), false);
385 emit object->basicSignal();
386 QCOMPARE(object->methodCalled(), true);
387 QCOMPARE(object->methodIntCalled(), false);
392 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
393 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
394 QVERIFY(object != 0);
395 QCOMPARE(object->methodCalled(), false);
396 QCOMPARE(object->methodIntCalled(), false);
397 emit object->basicSignal();
398 QCOMPARE(object->methodCalled(), false);
399 QCOMPARE(object->methodIntCalled(), true);
404 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
405 QObject *object = component.create();
406 QVERIFY(object != 0);
407 QCOMPARE(object->property("test").toInt(), 19);
412 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
413 QObject *object = component.create();
414 QVERIFY(object != 0);
415 QCOMPARE(object->property("test").toInt(), 19);
416 QCOMPARE(object->property("test2").toInt(), 17);
417 QCOMPARE(object->property("test3").toInt(), 16);
422 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
423 QObject *object = component.create();
424 QVERIFY(object != 0);
425 QCOMPARE(object->property("test").toInt(), 9);
430 void tst_qdeclarativeecmascript::bindingLoop()
432 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
433 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
434 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
435 QObject *object = component.create();
436 QVERIFY(object != 0);
440 void tst_qdeclarativeecmascript::basicExpressions_data()
442 QTest::addColumn<QString>("expression");
443 QTest::addColumn<QVariant>("result");
444 QTest::addColumn<bool>("nest");
446 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
447 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
448 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
449 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
450 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
451 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
452 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
453 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
454 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
455 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
456 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
457 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
458 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
459 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
460 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
461 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
462 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
463 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
464 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
467 void tst_qdeclarativeecmascript::basicExpressions()
469 QFETCH(QString, expression);
470 QFETCH(QVariant, result);
476 MyDefaultObject1 default1;
477 MyDefaultObject3 default3;
478 object1.setStringProperty("Object1");
479 object2.setStringProperty("Object2");
480 object3.setStringProperty("Object3");
482 QDeclarativeContext context(engine.rootContext());
483 QDeclarativeContext nestedContext(&context);
485 context.setContextObject(&default1);
486 context.setContextProperty("a", QVariant(1944));
487 context.setContextProperty("b", QVariant("Milk"));
488 context.setContextProperty("object", &object1);
489 context.setContextProperty("objectOverride", &object2);
490 nestedContext.setContextObject(&default3);
491 nestedContext.setContextProperty("b", QVariant("Cow"));
492 nestedContext.setContextProperty("objectOverride", &object3);
493 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
495 MyExpression expr(nest?&nestedContext:&context, expression);
496 QCOMPARE(expr.evaluate(), result);
499 void tst_qdeclarativeecmascript::arrayExpressions()
505 QDeclarativeContext context(engine.rootContext());
506 context.setContextProperty("a", &obj1);
507 context.setContextProperty("b", &obj2);
508 context.setContextProperty("c", &obj3);
510 MyExpression expr(&context, "[a, b, c, 10]");
511 QVariant result = expr.evaluate();
512 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
513 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
514 QCOMPARE(list.count(), 4);
515 QCOMPARE(list.at(0), &obj1);
516 QCOMPARE(list.at(1), &obj2);
517 QCOMPARE(list.at(2), &obj3);
518 QCOMPARE(list.at(3), (QObject *)0);
521 // Tests that modifying a context property will reevaluate expressions
522 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
524 QDeclarativeContext context(engine.rootContext());
527 MyQmlObject *object3 = new MyQmlObject;
529 object1.setStringProperty("Hello");
530 object2.setStringProperty("World");
532 context.setContextProperty("testProp", QVariant(1));
533 context.setContextProperty("testObj", &object1);
534 context.setContextProperty("testObj2", object3);
537 MyExpression expr(&context, "testProp + 1");
538 QCOMPARE(expr.changed, false);
539 QCOMPARE(expr.evaluate(), QVariant(2));
541 context.setContextProperty("testProp", QVariant(2));
542 QCOMPARE(expr.changed, true);
543 QCOMPARE(expr.evaluate(), QVariant(3));
547 MyExpression expr(&context, "testProp + testProp + testProp");
548 QCOMPARE(expr.changed, false);
549 QCOMPARE(expr.evaluate(), QVariant(6));
551 context.setContextProperty("testProp", QVariant(4));
552 QCOMPARE(expr.changed, true);
553 QCOMPARE(expr.evaluate(), QVariant(12));
557 MyExpression expr(&context, "testObj.stringProperty");
558 QCOMPARE(expr.changed, false);
559 QCOMPARE(expr.evaluate(), QVariant("Hello"));
561 context.setContextProperty("testObj", &object2);
562 QCOMPARE(expr.changed, true);
563 QCOMPARE(expr.evaluate(), QVariant("World"));
567 MyExpression expr(&context, "testObj.stringProperty /**/");
568 QCOMPARE(expr.changed, false);
569 QCOMPARE(expr.evaluate(), QVariant("World"));
571 context.setContextProperty("testObj", &object1);
572 QCOMPARE(expr.changed, true);
573 QCOMPARE(expr.evaluate(), QVariant("Hello"));
577 MyExpression expr(&context, "testObj2");
578 QCOMPARE(expr.changed, false);
579 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
585 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
587 QDeclarativeContext context(engine.rootContext());
591 context.setContextProperty("testObj", &object1);
593 object1.setStringProperty(QLatin1String("Hello"));
594 object2.setStringProperty(QLatin1String("Dog"));
595 object3.setStringProperty(QLatin1String("Cat"));
598 MyExpression expr(&context, "testObj.stringProperty");
599 QCOMPARE(expr.changed, false);
600 QCOMPARE(expr.evaluate(), QVariant("Hello"));
602 object1.setStringProperty(QLatin1String("World"));
603 QCOMPARE(expr.changed, true);
604 QCOMPARE(expr.evaluate(), QVariant("World"));
608 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
609 QCOMPARE(expr.changed, false);
610 QCOMPARE(expr.evaluate(), QVariant());
612 object1.setObjectProperty(&object2);
613 QCOMPARE(expr.changed, true);
614 expr.changed = false;
615 QCOMPARE(expr.evaluate(), QVariant("Dog"));
617 object1.setObjectProperty(&object3);
618 QCOMPARE(expr.changed, true);
619 expr.changed = false;
620 QCOMPARE(expr.evaluate(), QVariant("Cat"));
622 object1.setObjectProperty(0);
623 QCOMPARE(expr.changed, true);
624 expr.changed = false;
625 QCOMPARE(expr.evaluate(), QVariant());
627 object1.setObjectProperty(&object3);
628 QCOMPARE(expr.changed, true);
629 expr.changed = false;
630 QCOMPARE(expr.evaluate(), QVariant("Cat"));
632 object3.setStringProperty("Donkey");
633 QCOMPARE(expr.changed, true);
634 expr.changed = false;
635 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
639 void tst_qdeclarativeecmascript::deferredProperties()
641 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
642 MyDeferredObject *object =
643 qobject_cast<MyDeferredObject *>(component.create());
644 QVERIFY(object != 0);
645 QCOMPARE(object->value(), 0);
646 QVERIFY(object->objectProperty() == 0);
647 QVERIFY(object->objectProperty2() != 0);
648 qmlExecuteDeferred(object);
649 QCOMPARE(object->value(), 10);
650 QVERIFY(object->objectProperty() != 0);
651 MyQmlObject *qmlObject =
652 qobject_cast<MyQmlObject *>(object->objectProperty());
653 QVERIFY(qmlObject != 0);
654 QCOMPARE(qmlObject->value(), 10);
655 object->setValue(19);
656 QCOMPARE(qmlObject->value(), 19);
661 // Check errors on deferred properties are correctly emitted
662 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
664 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
665 MyDeferredObject *object =
666 qobject_cast<MyDeferredObject *>(component.create());
667 QVERIFY(object != 0);
668 QCOMPARE(object->value(), 0);
669 QVERIFY(object->objectProperty() == 0);
670 QVERIFY(object->objectProperty2() == 0);
672 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
673 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
675 qmlExecuteDeferred(object);
680 void tst_qdeclarativeecmascript::extensionObjects()
682 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
683 MyExtendedObject *object =
684 qobject_cast<MyExtendedObject *>(component.create());
685 QVERIFY(object != 0);
686 QCOMPARE(object->baseProperty(), 13);
687 QCOMPARE(object->coreProperty(), 9);
688 object->setProperty("extendedProperty", QVariant(11));
689 object->setProperty("baseExtendedProperty", QVariant(92));
690 QCOMPARE(object->coreProperty(), 11);
691 QCOMPARE(object->baseProperty(), 92);
693 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
695 QCOMPARE(nested->baseProperty(), 13);
696 QCOMPARE(nested->coreProperty(), 9);
697 nested->setProperty("extendedProperty", QVariant(11));
698 nested->setProperty("baseExtendedProperty", QVariant(92));
699 QCOMPARE(nested->coreProperty(), 11);
700 QCOMPARE(nested->baseProperty(), 92);
705 void tst_qdeclarativeecmascript::overrideExtensionProperties()
707 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
708 OverrideDefaultPropertyObject *object =
709 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
710 QVERIFY(object != 0);
711 QVERIFY(object->secondProperty() != 0);
712 QVERIFY(object->firstProperty() == 0);
717 void tst_qdeclarativeecmascript::attachedProperties()
720 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
721 QObject *object = component.create();
722 QVERIFY(object != 0);
723 QCOMPARE(object->property("a").toInt(), 19);
724 QCOMPARE(object->property("b").toInt(), 19);
725 QCOMPARE(object->property("c").toInt(), 19);
726 QCOMPARE(object->property("d").toInt(), 19);
731 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
732 QObject *object = component.create();
733 QVERIFY(object != 0);
734 QCOMPARE(object->property("a").toInt(), 26);
735 QCOMPARE(object->property("b").toInt(), 26);
736 QCOMPARE(object->property("c").toInt(), 26);
737 QCOMPARE(object->property("d").toInt(), 26);
743 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
744 QObject *object = component.create();
745 QVERIFY(object != 0);
747 QMetaObject::invokeMethod(object, "writeValue2");
749 MyQmlAttachedObject *attached =
750 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
751 QVERIFY(attached != 0);
753 QCOMPARE(attached->value2(), 9);
758 void tst_qdeclarativeecmascript::enums()
762 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
763 QObject *object = component.create();
764 QVERIFY(object != 0);
766 QCOMPARE(object->property("a").toInt(), 0);
767 QCOMPARE(object->property("b").toInt(), 1);
768 QCOMPARE(object->property("c").toInt(), 2);
769 QCOMPARE(object->property("d").toInt(), 3);
770 QCOMPARE(object->property("e").toInt(), 0);
771 QCOMPARE(object->property("f").toInt(), 1);
772 QCOMPARE(object->property("g").toInt(), 2);
773 QCOMPARE(object->property("h").toInt(), 3);
774 QCOMPARE(object->property("i").toInt(), 19);
775 QCOMPARE(object->property("j").toInt(), 19);
779 // Non-existent enums
781 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
783 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
784 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
785 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
786 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
788 QObject *object = component.create();
789 QVERIFY(object != 0);
790 QCOMPARE(object->property("a").toInt(), 0);
791 QCOMPARE(object->property("b").toInt(), 0);
797 void tst_qdeclarativeecmascript::valueTypeFunctions()
799 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
800 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
802 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
803 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
809 Tests that writing a constant to a property with a binding on it disables the
812 void tst_qdeclarativeecmascript::constantsOverrideBindings()
816 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
817 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
818 QVERIFY(object != 0);
820 QCOMPARE(object->property("c2").toInt(), 0);
821 object->setProperty("c1", QVariant(9));
822 QCOMPARE(object->property("c2").toInt(), 9);
824 emit object->basicSignal();
826 QCOMPARE(object->property("c2").toInt(), 13);
827 object->setProperty("c1", QVariant(8));
828 QCOMPARE(object->property("c2").toInt(), 13);
833 // During construction
835 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
836 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
837 QVERIFY(object != 0);
839 QCOMPARE(object->property("c1").toInt(), 0);
840 QCOMPARE(object->property("c2").toInt(), 10);
841 object->setProperty("c1", QVariant(9));
842 QCOMPARE(object->property("c1").toInt(), 9);
843 QCOMPARE(object->property("c2").toInt(), 10);
851 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
852 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
853 QVERIFY(object != 0);
855 QCOMPARE(object->property("c2").toInt(), 0);
856 object->setProperty("c1", QVariant(9));
857 QCOMPARE(object->property("c2").toInt(), 9);
859 object->setProperty("c2", QVariant(13));
860 QCOMPARE(object->property("c2").toInt(), 13);
861 object->setProperty("c1", QVariant(7));
862 QCOMPARE(object->property("c1").toInt(), 7);
863 QCOMPARE(object->property("c2").toInt(), 13);
871 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
872 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
873 QVERIFY(object != 0);
875 QCOMPARE(object->property("c1").toInt(), 0);
876 QCOMPARE(object->property("c3").toInt(), 10);
877 object->setProperty("c1", QVariant(9));
878 QCOMPARE(object->property("c1").toInt(), 9);
879 QCOMPARE(object->property("c3").toInt(), 10);
886 Tests that assigning a binding to a property that already has a binding causes
887 the original binding to be disabled.
889 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
891 QDeclarativeComponent component(&engine,
892 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
893 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
894 QVERIFY(object != 0);
896 QCOMPARE(object->property("c1").toInt(), 0);
897 QCOMPARE(object->property("c2").toInt(), 0);
898 QCOMPARE(object->property("c3").toInt(), 0);
900 object->setProperty("c1", QVariant(9));
901 QCOMPARE(object->property("c1").toInt(), 9);
902 QCOMPARE(object->property("c2").toInt(), 0);
903 QCOMPARE(object->property("c3").toInt(), 0);
905 object->setProperty("c3", QVariant(8));
906 QCOMPARE(object->property("c1").toInt(), 9);
907 QCOMPARE(object->property("c2").toInt(), 8);
908 QCOMPARE(object->property("c3").toInt(), 8);
914 Access a non-existent attached object.
916 Tests for a regression where this used to crash.
918 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
920 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
922 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
923 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
925 QObject *object = component.create();
926 QVERIFY(object != 0);
931 void tst_qdeclarativeecmascript::scope()
934 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
935 QObject *object = component.create();
936 QVERIFY(object != 0);
938 QCOMPARE(object->property("test1").toInt(), 1);
939 QCOMPARE(object->property("test2").toInt(), 2);
940 QCOMPARE(object->property("test3").toString(), QString("1Test"));
941 QCOMPARE(object->property("test4").toString(), QString("2Test"));
942 QCOMPARE(object->property("test5").toInt(), 1);
943 QCOMPARE(object->property("test6").toInt(), 1);
944 QCOMPARE(object->property("test7").toInt(), 2);
945 QCOMPARE(object->property("test8").toInt(), 2);
946 QCOMPARE(object->property("test9").toInt(), 1);
947 QCOMPARE(object->property("test10").toInt(), 3);
953 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
954 QObject *object = component.create();
955 QVERIFY(object != 0);
957 QCOMPARE(object->property("test1").toInt(), 19);
958 QCOMPARE(object->property("test2").toInt(), 19);
959 QCOMPARE(object->property("test3").toInt(), 14);
960 QCOMPARE(object->property("test4").toInt(), 14);
961 QCOMPARE(object->property("test5").toInt(), 24);
962 QCOMPARE(object->property("test6").toInt(), 24);
968 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
969 QObject *object = component.create();
970 QVERIFY(object != 0);
972 QCOMPARE(object->property("test1").toBool(), true);
973 QCOMPARE(object->property("test2").toBool(), true);
974 QCOMPARE(object->property("test3").toBool(), true);
979 // Signal argument scope
981 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
982 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
983 QVERIFY(object != 0);
985 QCOMPARE(object->property("test").toInt(), 0);
986 QCOMPARE(object->property("test2").toString(), QString());
988 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
990 QCOMPARE(object->property("test").toInt(), 13);
991 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
997 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
998 QObject *object = component.create();
999 QVERIFY(object != 0);
1001 QCOMPARE(object->property("test1").toBool(), true);
1002 QCOMPARE(object->property("test2").toBool(), true);
1008 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
1009 QObject *object = component.create();
1010 QVERIFY(object != 0);
1012 QCOMPARE(object->property("test").toBool(), true);
1018 // In 4.7, non-library javascript files that had no imports shared the imports of their
1019 // importing context
1020 void tst_qdeclarativeecmascript::importScope()
1022 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1023 QObject *o = component.create();
1026 QCOMPARE(o->property("test").toInt(), 240);
1032 Tests that "any" type passes through a synthesized signal parameter. This
1033 is essentially a test of QDeclarativeMetaType::copy()
1035 void tst_qdeclarativeecmascript::signalParameterTypes()
1037 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1038 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1039 QVERIFY(object != 0);
1041 emit object->basicSignal();
1043 QCOMPARE(object->property("intProperty").toInt(), 10);
1044 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1045 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1046 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1047 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1048 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1054 Test that two JS objects for the same QObject compare as equal.
1056 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1058 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1059 QObject *object = component.create();
1060 QVERIFY(object != 0);
1062 QCOMPARE(object->property("test1").toBool(), true);
1063 QCOMPARE(object->property("test2").toBool(), true);
1064 QCOMPARE(object->property("test3").toBool(), true);
1065 QCOMPARE(object->property("test4").toBool(), true);
1066 QCOMPARE(object->property("test5").toBool(), true);
1072 Confirm bindings and alias properties can coexist.
1074 Tests for a regression where the binding would not reevaluate.
1076 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1078 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1079 QObject *object = component.create();
1080 QVERIFY(object != 0);
1082 QCOMPARE(object->property("c2").toInt(), 3);
1083 QCOMPARE(object->property("c3").toInt(), 3);
1085 object->setProperty("c2", QVariant(19));
1087 QCOMPARE(object->property("c2").toInt(), 19);
1088 QCOMPARE(object->property("c3").toInt(), 19);
1094 Ensure that we can write undefined value to an alias property,
1095 and that the aliased property is reset correctly if possible.
1097 void tst_qdeclarativeecmascript::aliasPropertyReset()
1099 QObject *object = 0;
1101 // test that a manual write (of undefined) to a resettable aliased property succeeds
1102 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1103 object = c1.create();
1104 QVERIFY(object != 0);
1105 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1106 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1107 QMetaObject::invokeMethod(object, "resetAliased");
1108 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1109 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1112 // test that a manual write (of undefined) to a resettable alias property succeeds
1113 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1114 object = c2.create();
1115 QVERIFY(object != 0);
1116 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1117 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1118 QMetaObject::invokeMethod(object, "resetAlias");
1119 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1120 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1123 // test that an alias to a bound property works correctly
1124 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1125 object = c3.create();
1126 QVERIFY(object != 0);
1127 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1128 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1129 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1130 QMetaObject::invokeMethod(object, "resetAlias");
1131 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1132 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1133 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1136 // test that a manual write (of undefined) to a resettable alias property
1137 // whose aliased property's object has been deleted, does not crash.
1138 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1139 object = c4.create();
1140 QVERIFY(object != 0);
1141 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1142 QObject *loader = object->findChild<QObject*>("loader");
1143 QVERIFY(loader != 0);
1145 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1146 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1147 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1148 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1149 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1152 // test that binding an alias property to an undefined value works correctly
1153 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1154 object = c5.create();
1155 QVERIFY(object != 0);
1156 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1159 // test that a manual write (of undefined) to a non-resettable property fails properly
1160 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1161 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1162 QDeclarativeComponent e1(&engine, url);
1163 object = e1.create();
1164 QVERIFY(object != 0);
1165 QCOMPARE(object->property("intAlias").value<int>(), 12);
1166 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1167 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1168 QMetaObject::invokeMethod(object, "resetAlias");
1169 QCOMPARE(object->property("intAlias").value<int>(), 12);
1170 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1174 void tst_qdeclarativeecmascript::dynamicCreation_data()
1176 QTest::addColumn<QString>("method");
1177 QTest::addColumn<QString>("createdName");
1179 QTest::newRow("One") << "createOne" << "objectOne";
1180 QTest::newRow("Two") << "createTwo" << "objectTwo";
1181 QTest::newRow("Three") << "createThree" << "objectThree";
1185 Test using createQmlObject to dynamically generate an item
1186 Also using createComponent is tested.
1188 void tst_qdeclarativeecmascript::dynamicCreation()
1190 QFETCH(QString, method);
1191 QFETCH(QString, createdName);
1193 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1194 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1195 QVERIFY(object != 0);
1197 QMetaObject::invokeMethod(object, method.toUtf8());
1198 QObject *created = object->objectProperty();
1200 QCOMPARE(created->objectName(), createdName);
1206 Tests the destroy function
1208 void tst_qdeclarativeecmascript::dynamicDestruction()
1211 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1212 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1213 QVERIFY(object != 0);
1214 QDeclarativeGuard<QObject> createdQmlObject = 0;
1216 QMetaObject::invokeMethod(object, "create");
1217 createdQmlObject = object->objectProperty();
1218 QVERIFY(createdQmlObject);
1219 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1221 QMetaObject::invokeMethod(object, "killOther");
1222 QVERIFY(createdQmlObject);
1223 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1224 QVERIFY(createdQmlObject);
1225 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1226 if (createdQmlObject) {
1228 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1231 QVERIFY(!createdQmlObject);
1233 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1234 QMetaObject::invokeMethod(object, "killMe");
1237 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1242 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1243 QObject *o = component.create();
1246 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1248 QMetaObject::invokeMethod(o, "create");
1250 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1252 QMetaObject::invokeMethod(o, "destroy");
1254 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1256 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1263 tests that id.toString() works
1265 void tst_qdeclarativeecmascript::objectToString()
1267 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1268 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1269 QVERIFY(object != 0);
1270 QMetaObject::invokeMethod(object, "testToString");
1271 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1272 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1278 tests that id.hasOwnProperty() works
1280 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1282 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1283 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1284 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1285 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1287 QDeclarativeComponent component(&engine, url);
1288 QObject *object = component.create();
1289 QVERIFY(object != 0);
1291 // test QObjects in QML
1292 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1293 QVERIFY(object->property("result").value<bool>() == true);
1294 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1295 QVERIFY(object->property("result").value<bool>() == false);
1297 // now test other types in QML
1298 QObject *child = object->findChild<QObject*>("typeObj");
1299 QVERIFY(child != 0);
1300 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1301 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1302 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1303 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1304 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1305 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1306 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1307 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1308 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1309 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1310 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1311 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1313 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1314 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1315 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1316 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1317 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1318 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1319 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1320 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1321 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1327 Tests bindings that indirectly cause their own deletion work.
1329 This test is best run under valgrind to ensure no invalid memory access occur.
1331 void tst_qdeclarativeecmascript::selfDeletingBinding()
1334 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1335 QObject *object = component.create();
1336 QVERIFY(object != 0);
1337 object->setProperty("triggerDelete", true);
1342 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1343 QObject *object = component.create();
1344 QVERIFY(object != 0);
1345 object->setProperty("triggerDelete", true);
1351 Test that extended object properties can be accessed.
1353 This test a regression where this used to crash. The issue was specificially
1354 for extended objects that did not include a synthesized meta object (so non-root
1355 and no synthesiszed properties).
1357 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1359 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1360 QObject *object = component.create();
1361 QVERIFY(object != 0);
1366 Test that extended object properties can be accessed correctly.
1368 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
1370 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup2.qml"));
1371 QObject *object = component.create();
1372 QVERIFY(object != 0);
1374 QVariant returnValue;
1375 QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
1376 QCOMPARE(returnValue.toInt(), 42);
1381 Test file/lineNumbers for binding/Script errors.
1383 void tst_qdeclarativeecmascript::scriptErrors()
1385 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1386 QString url = component.url().toString();
1388 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1389 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1390 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1391 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1392 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1393 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1394 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1395 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1397 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1398 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1399 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1400 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1401 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1402 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1403 QVERIFY(object != 0);
1405 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1406 emit object->basicSignal();
1408 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1409 emit object->anotherBasicSignal();
1411 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1412 emit object->thirdBasicSignal();
1418 Test file/lineNumbers for inline functions.
1420 void tst_qdeclarativeecmascript::functionErrors()
1422 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1423 QString url = component.url().toString();
1425 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1427 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1429 QObject *object = component.create();
1430 QVERIFY(object != 0);
1433 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1434 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
1435 url = componentTwo.url().toString();
1436 object = componentTwo.create();
1437 QVERIFY(object != 0);
1439 QString srpname = object->property("srp_name").toString();
1441 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1442 + QLatin1String(" is not a function");
1443 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1444 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1449 Test various errors that can occur when assigning a property from script
1451 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1453 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1455 QString url = component.url().toString();
1457 QObject *object = component.create();
1458 QVERIFY(object != 0);
1460 QCOMPARE(object->property("test1").toBool(), true);
1461 QCOMPARE(object->property("test2").toBool(), true);
1467 Test bindings still work when the reeval is triggered from within
1470 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1472 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1473 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1474 QVERIFY(object != 0);
1476 QCOMPARE(object->property("base").toReal(), 50.);
1477 QCOMPARE(object->property("test1").toReal(), 50.);
1478 QCOMPARE(object->property("test2").toReal(), 50.);
1480 object->basicSignal();
1482 QCOMPARE(object->property("base").toReal(), 200.);
1483 QCOMPARE(object->property("test1").toReal(), 200.);
1484 QCOMPARE(object->property("test2").toReal(), 200.);
1486 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1488 QCOMPARE(object->property("base").toReal(), 400.);
1489 QCOMPARE(object->property("test1").toReal(), 400.);
1490 QCOMPARE(object->property("test2").toReal(), 400.);
1496 Test that list properties can be iterated from ECMAScript
1498 void tst_qdeclarativeecmascript::listProperties()
1500 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1501 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1502 QVERIFY(object != 0);
1504 QCOMPARE(object->property("test1").toInt(), 21);
1505 QCOMPARE(object->property("test2").toInt(), 2);
1506 QCOMPARE(object->property("test3").toBool(), true);
1507 QCOMPARE(object->property("test4").toBool(), true);
1512 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1514 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1515 QString url = component.url().toString();
1517 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1519 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1520 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1521 QVERIFY(object != 0);
1523 QCOMPARE(object->property("test").toBool(), false);
1525 MyQmlObject object2;
1526 MyQmlObject object3;
1527 object2.setObjectProperty(&object3);
1528 object->setObjectProperty(&object2);
1530 QCOMPARE(object->property("test").toBool(), true);
1535 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1537 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1538 QString url = component.url().toString();
1540 QString warning = component.url().toString() + ":6: Error: JS exception";
1542 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1543 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1544 QVERIFY(object != 0);
1548 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1550 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1551 QString url = component.url().toString();
1553 QString warning = component.url().toString() + ":5: Error: JS exception";
1555 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1556 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1557 QVERIFY(object != 0);
1561 static int transientErrorsMsgCount = 0;
1562 static void transientErrorsMsgHandler(QtMsgType, const char *)
1564 ++transientErrorsMsgCount;
1567 // Check that transient binding errors are not displayed
1568 void tst_qdeclarativeecmascript::transientErrors()
1571 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1573 transientErrorsMsgCount = 0;
1574 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1576 QObject *object = component.create();
1577 QVERIFY(object != 0);
1579 qInstallMsgHandler(old);
1581 QCOMPARE(transientErrorsMsgCount, 0);
1586 // One binding erroring multiple times, but then resolving
1588 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1590 transientErrorsMsgCount = 0;
1591 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1593 QObject *object = component.create();
1594 QVERIFY(object != 0);
1596 qInstallMsgHandler(old);
1598 QCOMPARE(transientErrorsMsgCount, 0);
1604 // Check that errors during shutdown are minimized
1605 void tst_qdeclarativeecmascript::shutdownErrors()
1607 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1608 QObject *object = component.create();
1609 QVERIFY(object != 0);
1611 transientErrorsMsgCount = 0;
1612 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1616 qInstallMsgHandler(old);
1617 QCOMPARE(transientErrorsMsgCount, 0);
1620 void tst_qdeclarativeecmascript::compositePropertyType()
1622 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1624 QTest::ignoreMessage(QtDebugMsg, "hello world");
1625 QObject *object = qobject_cast<QObject *>(component.create());
1630 void tst_qdeclarativeecmascript::jsObject()
1632 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1633 QObject *object = component.create();
1634 QVERIFY(object != 0);
1636 QCOMPARE(object->property("test").toInt(), 92);
1641 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1644 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1645 QObject *object = component.create();
1646 QVERIFY(object != 0);
1648 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1650 object->setProperty("setUndefined", true);
1652 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1654 object->setProperty("setUndefined", false);
1656 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1661 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1662 QObject *object = component.create();
1663 QVERIFY(object != 0);
1665 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1667 QMetaObject::invokeMethod(object, "doReset");
1669 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1675 // Aliases to variant properties should work
1676 void tst_qdeclarativeecmascript::qtbug_22464()
1678 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1679 QObject *object = component.create();
1680 QVERIFY(object != 0);
1682 QCOMPARE(object->property("test").toBool(), true);
1687 void tst_qdeclarativeecmascript::qtbug_21580()
1689 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
1691 QObject *object = component.create();
1692 QVERIFY(object != 0);
1694 QCOMPARE(object->property("test").toBool(), true);
1700 void tst_qdeclarativeecmascript::bug1()
1702 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1703 QObject *object = component.create();
1704 QVERIFY(object != 0);
1706 QCOMPARE(object->property("test").toInt(), 14);
1708 object->setProperty("a", 11);
1710 QCOMPARE(object->property("test").toInt(), 3);
1712 object->setProperty("b", true);
1714 QCOMPARE(object->property("test").toInt(), 9);
1719 void tst_qdeclarativeecmascript::bug2()
1721 QDeclarativeComponent component(&engine);
1722 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1724 QObject *object = component.create();
1725 QVERIFY(object != 0);
1730 // Don't crash in createObject when the component has errors.
1731 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1733 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1734 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1735 QVERIFY(object != 0);
1737 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1738 QMetaObject::invokeMethod(object, "dontCrash");
1739 QObject *created = object->objectProperty();
1740 QVERIFY(created == 0);
1745 // ownership transferred to JS, ensure that GC runs the dtor
1746 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1749 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1751 // allow the engine to go out of scope too.
1753 QDeclarativeEngine dcoEngine;
1754 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1755 QObject *object = component.create();
1756 QVERIFY(object != 0);
1757 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1758 QVERIFY(mdcdo != 0);
1759 mdcdo->setDtorCount(&dtorCount);
1761 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1762 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1764 // we do this once manually, but it should be done automatically
1765 // when the engine goes out of scope (since it should gc in dtor)
1766 QMetaObject::invokeMethod(object, "performGc");
1769 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1775 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1776 QCOMPARE(dtorCount, expectedDtorCount);
1780 void tst_qdeclarativeecmascript::regExpBug()
1782 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1783 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1784 QVERIFY(object != 0);
1785 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1789 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1791 QString functionSource = QLatin1String("(function(object) { return ") +
1792 QLatin1String(source) + QLatin1String(" })");
1794 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1797 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1798 if (function.IsEmpty())
1800 v8::Handle<v8::Value> args[] = { o };
1801 function->Call(engine->global(), 1, args);
1802 return tc.HasCaught();
1805 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1806 const char *source, v8::Handle<v8::Value> result)
1808 QString functionSource = QLatin1String("(function(object) { return ") +
1809 QLatin1String(source) + QLatin1String(" })");
1811 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1814 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1815 if (function.IsEmpty())
1817 v8::Handle<v8::Value> args[] = { o };
1819 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1824 return value->StrictEquals(result);
1827 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1830 QString functionSource = QLatin1String("(function(object) { return ") +
1831 QLatin1String(source) + QLatin1String(" })");
1833 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1835 return v8::Handle<v8::Value>();
1836 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1837 if (function.IsEmpty())
1838 return v8::Handle<v8::Value>();
1839 v8::Handle<v8::Value> args[] = { o };
1841 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1844 return v8::Handle<v8::Value>();
1848 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1849 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1850 #define EVALUATE(source) evaluate(engine, object, source)
1852 void tst_qdeclarativeecmascript::callQtInvokables()
1854 MyInvokableObject o;
1856 QDeclarativeEngine qmlengine;
1857 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1859 QV8Engine *engine = ep->v8engine();
1861 v8::HandleScope handle_scope;
1862 v8::Context::Scope scope(engine->context());
1864 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1866 // Non-existent methods
1868 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1869 QCOMPARE(o.error(), false);
1870 QCOMPARE(o.invoked(), -1);
1871 QCOMPARE(o.actuals().count(), 0);
1874 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1875 QCOMPARE(o.error(), false);
1876 QCOMPARE(o.invoked(), -1);
1877 QCOMPARE(o.actuals().count(), 0);
1879 // Insufficient arguments
1881 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1882 QCOMPARE(o.error(), false);
1883 QCOMPARE(o.invoked(), -1);
1884 QCOMPARE(o.actuals().count(), 0);
1887 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1888 QCOMPARE(o.error(), false);
1889 QCOMPARE(o.invoked(), -1);
1890 QCOMPARE(o.actuals().count(), 0);
1892 // Excessive arguments
1894 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1895 QCOMPARE(o.error(), false);
1896 QCOMPARE(o.invoked(), 8);
1897 QCOMPARE(o.actuals().count(), 1);
1898 QCOMPARE(o.actuals().at(0), QVariant(10));
1901 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1902 QCOMPARE(o.error(), false);
1903 QCOMPARE(o.invoked(), 9);
1904 QCOMPARE(o.actuals().count(), 2);
1905 QCOMPARE(o.actuals().at(0), QVariant(10));
1906 QCOMPARE(o.actuals().at(1), QVariant(11));
1908 // Test return types
1910 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1911 QCOMPARE(o.error(), false);
1912 QCOMPARE(o.invoked(), 0);
1913 QCOMPARE(o.actuals().count(), 0);
1916 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1917 QCOMPARE(o.error(), false);
1918 QCOMPARE(o.invoked(), 1);
1919 QCOMPARE(o.actuals().count(), 0);
1922 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1923 QCOMPARE(o.error(), false);
1924 QCOMPARE(o.invoked(), 2);
1925 QCOMPARE(o.actuals().count(), 0);
1929 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1930 QVERIFY(!ret.IsEmpty());
1931 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1932 QCOMPARE(o.error(), false);
1933 QCOMPARE(o.invoked(), 3);
1934 QCOMPARE(o.actuals().count(), 0);
1939 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1940 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1941 QCOMPARE(o.error(), false);
1942 QCOMPARE(o.invoked(), 4);
1943 QCOMPARE(o.actuals().count(), 0);
1947 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1948 QCOMPARE(o.error(), false);
1949 QCOMPARE(o.invoked(), 5);
1950 QCOMPARE(o.actuals().count(), 0);
1954 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1955 QVERIFY(ret->IsString());
1956 QCOMPARE(engine->toString(ret), QString("Hello world"));
1957 QCOMPARE(o.error(), false);
1958 QCOMPARE(o.invoked(), 6);
1959 QCOMPARE(o.actuals().count(), 0);
1963 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1964 QCOMPARE(o.error(), false);
1965 QCOMPARE(o.invoked(), 7);
1966 QCOMPARE(o.actuals().count(), 0);
1970 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1971 QCOMPARE(o.error(), false);
1972 QCOMPARE(o.invoked(), 8);
1973 QCOMPARE(o.actuals().count(), 1);
1974 QCOMPARE(o.actuals().at(0), QVariant(94));
1977 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1978 QCOMPARE(o.error(), false);
1979 QCOMPARE(o.invoked(), 8);
1980 QCOMPARE(o.actuals().count(), 1);
1981 QCOMPARE(o.actuals().at(0), QVariant(94));
1984 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1985 QCOMPARE(o.error(), false);
1986 QCOMPARE(o.invoked(), 8);
1987 QCOMPARE(o.actuals().count(), 1);
1988 QCOMPARE(o.actuals().at(0), QVariant(0));
1991 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1992 QCOMPARE(o.error(), false);
1993 QCOMPARE(o.invoked(), 8);
1994 QCOMPARE(o.actuals().count(), 1);
1995 QCOMPARE(o.actuals().at(0), QVariant(0));
1998 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1999 QCOMPARE(o.error(), false);
2000 QCOMPARE(o.invoked(), 8);
2001 QCOMPARE(o.actuals().count(), 1);
2002 QCOMPARE(o.actuals().at(0), QVariant(0));
2005 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2006 QCOMPARE(o.error(), false);
2007 QCOMPARE(o.invoked(), 8);
2008 QCOMPARE(o.actuals().count(), 1);
2009 QCOMPARE(o.actuals().at(0), QVariant(0));
2012 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2013 QCOMPARE(o.error(), false);
2014 QCOMPARE(o.invoked(), 9);
2015 QCOMPARE(o.actuals().count(), 2);
2016 QCOMPARE(o.actuals().at(0), QVariant(122));
2017 QCOMPARE(o.actuals().at(1), QVariant(9));
2020 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2021 QCOMPARE(o.error(), false);
2022 QCOMPARE(o.invoked(), 10);
2023 QCOMPARE(o.actuals().count(), 1);
2024 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2027 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2028 QCOMPARE(o.error(), false);
2029 QCOMPARE(o.invoked(), 10);
2030 QCOMPARE(o.actuals().count(), 1);
2031 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2034 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2035 QCOMPARE(o.error(), false);
2036 QCOMPARE(o.invoked(), 10);
2037 QCOMPARE(o.actuals().count(), 1);
2038 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2041 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2042 QCOMPARE(o.error(), false);
2043 QCOMPARE(o.invoked(), 10);
2044 QCOMPARE(o.actuals().count(), 1);
2045 QCOMPARE(o.actuals().at(0), QVariant(0));
2048 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2049 QCOMPARE(o.error(), false);
2050 QCOMPARE(o.invoked(), 10);
2051 QCOMPARE(o.actuals().count(), 1);
2052 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2055 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2056 QCOMPARE(o.error(), false);
2057 QCOMPARE(o.invoked(), 10);
2058 QCOMPARE(o.actuals().count(), 1);
2059 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2062 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2063 QCOMPARE(o.error(), false);
2064 QCOMPARE(o.invoked(), 11);
2065 QCOMPARE(o.actuals().count(), 1);
2066 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2069 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2070 QCOMPARE(o.error(), false);
2071 QCOMPARE(o.invoked(), 11);
2072 QCOMPARE(o.actuals().count(), 1);
2073 QCOMPARE(o.actuals().at(0), QVariant("19"));
2077 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2078 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2079 QCOMPARE(o.error(), false);
2080 QCOMPARE(o.invoked(), 11);
2081 QCOMPARE(o.actuals().count(), 1);
2082 QCOMPARE(o.actuals().at(0), QVariant(expected));
2086 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2087 QCOMPARE(o.error(), false);
2088 QCOMPARE(o.invoked(), 11);
2089 QCOMPARE(o.actuals().count(), 1);
2090 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2093 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2094 QCOMPARE(o.error(), false);
2095 QCOMPARE(o.invoked(), 11);
2096 QCOMPARE(o.actuals().count(), 1);
2097 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2100 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2101 QCOMPARE(o.error(), false);
2102 QCOMPARE(o.invoked(), 12);
2103 QCOMPARE(o.actuals().count(), 1);
2104 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2107 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2108 QCOMPARE(o.error(), false);
2109 QCOMPARE(o.invoked(), 12);
2110 QCOMPARE(o.actuals().count(), 1);
2111 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2114 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2115 QCOMPARE(o.error(), false);
2116 QCOMPARE(o.invoked(), 12);
2117 QCOMPARE(o.actuals().count(), 1);
2118 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2121 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2122 QCOMPARE(o.error(), false);
2123 QCOMPARE(o.invoked(), 12);
2124 QCOMPARE(o.actuals().count(), 1);
2125 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2128 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2129 QCOMPARE(o.error(), false);
2130 QCOMPARE(o.invoked(), 12);
2131 QCOMPARE(o.actuals().count(), 1);
2132 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2135 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2136 QCOMPARE(o.error(), false);
2137 QCOMPARE(o.invoked(), 12);
2138 QCOMPARE(o.actuals().count(), 1);
2139 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2142 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2143 QCOMPARE(o.error(), false);
2144 QCOMPARE(o.invoked(), 13);
2145 QCOMPARE(o.actuals().count(), 1);
2146 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2149 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2150 QCOMPARE(o.error(), false);
2151 QCOMPARE(o.invoked(), 13);
2152 QCOMPARE(o.actuals().count(), 1);
2153 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2156 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2157 QCOMPARE(o.error(), false);
2158 QCOMPARE(o.invoked(), 13);
2159 QCOMPARE(o.actuals().count(), 1);
2160 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2163 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2164 QCOMPARE(o.error(), false);
2165 QCOMPARE(o.invoked(), 13);
2166 QCOMPARE(o.actuals().count(), 1);
2167 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2170 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2171 QCOMPARE(o.error(), false);
2172 QCOMPARE(o.invoked(), 13);
2173 QCOMPARE(o.actuals().count(), 1);
2174 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2177 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2178 QCOMPARE(o.error(), false);
2179 QCOMPARE(o.invoked(), 14);
2180 QCOMPARE(o.actuals().count(), 1);
2181 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2184 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2185 QCOMPARE(o.error(), false);
2186 QCOMPARE(o.invoked(), 14);
2187 QCOMPARE(o.actuals().count(), 1);
2188 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2191 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2192 QCOMPARE(o.error(), false);
2193 QCOMPARE(o.invoked(), 14);
2194 QCOMPARE(o.actuals().count(), 1);
2195 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2198 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2199 QCOMPARE(o.error(), false);
2200 QCOMPARE(o.invoked(), 14);
2201 QCOMPARE(o.actuals().count(), 1);
2202 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2205 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2206 QCOMPARE(o.error(), false);
2207 QCOMPARE(o.invoked(), 15);
2208 QCOMPARE(o.actuals().count(), 2);
2209 QCOMPARE(o.actuals().at(0), QVariant(4));
2210 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2213 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2214 QCOMPARE(o.error(), false);
2215 QCOMPARE(o.invoked(), 15);
2216 QCOMPARE(o.actuals().count(), 2);
2217 QCOMPARE(o.actuals().at(0), QVariant(8));
2218 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2221 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2222 QCOMPARE(o.error(), false);
2223 QCOMPARE(o.invoked(), 15);
2224 QCOMPARE(o.actuals().count(), 2);
2225 QCOMPARE(o.actuals().at(0), QVariant(3));
2226 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2229 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2230 QCOMPARE(o.error(), false);
2231 QCOMPARE(o.invoked(), 15);
2232 QCOMPARE(o.actuals().count(), 2);
2233 QCOMPARE(o.actuals().at(0), QVariant(44));
2234 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2237 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2238 QCOMPARE(o.error(), false);
2239 QCOMPARE(o.invoked(), -1);
2240 QCOMPARE(o.actuals().count(), 0);
2243 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2244 QCOMPARE(o.error(), false);
2245 QCOMPARE(o.invoked(), 16);
2246 QCOMPARE(o.actuals().count(), 1);
2247 QCOMPARE(o.actuals().at(0), QVariant(10));
2250 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2251 QCOMPARE(o.error(), false);
2252 QCOMPARE(o.invoked(), 17);
2253 QCOMPARE(o.actuals().count(), 2);
2254 QCOMPARE(o.actuals().at(0), QVariant(10));
2255 QCOMPARE(o.actuals().at(1), QVariant(11));
2258 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2259 QCOMPARE(o.error(), false);
2260 QCOMPARE(o.invoked(), 18);
2261 QCOMPARE(o.actuals().count(), 1);
2262 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2265 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2266 QCOMPARE(o.error(), false);
2267 QCOMPARE(o.invoked(), 19);
2268 QCOMPARE(o.actuals().count(), 1);
2269 QCOMPARE(o.actuals().at(0), QVariant(9));
2272 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2273 QCOMPARE(o.error(), false);
2274 QCOMPARE(o.invoked(), 20);
2275 QCOMPARE(o.actuals().count(), 2);
2276 QCOMPARE(o.actuals().at(0), QVariant(10));
2277 QCOMPARE(o.actuals().at(1), QVariant(19));
2280 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2281 QCOMPARE(o.error(), false);
2282 QCOMPARE(o.invoked(), 20);
2283 QCOMPARE(o.actuals().count(), 2);
2284 QCOMPARE(o.actuals().at(0), QVariant(10));
2285 QCOMPARE(o.actuals().at(1), QVariant(13));
2288 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2289 QCOMPARE(o.error(), false);
2290 QCOMPARE(o.invoked(), -3);
2291 QCOMPARE(o.actuals().count(), 1);
2292 QCOMPARE(o.actuals().at(0), QVariant(9));
2295 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2296 QCOMPARE(o.error(), false);
2297 QCOMPARE(o.invoked(), 21);
2298 QCOMPARE(o.actuals().count(), 2);
2299 QCOMPARE(o.actuals().at(0), QVariant(9));
2300 QCOMPARE(o.actuals().at(1), QVariant());
2303 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2304 QCOMPARE(o.error(), false);
2305 QCOMPARE(o.invoked(), 21);
2306 QCOMPARE(o.actuals().count(), 2);
2307 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2308 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2311 // QTBUG-13047 (check that you can pass registered object types as args)
2312 void tst_qdeclarativeecmascript::invokableObjectArg()
2314 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2316 QObject *o = component.create();
2318 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2320 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2325 // QTBUG-13047 (check that you can return registered object types from methods)
2326 void tst_qdeclarativeecmascript::invokableObjectRet()
2328 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2330 QObject *o = component.create();
2332 QCOMPARE(o->property("test").toBool(), true);
2337 void tst_qdeclarativeecmascript::listToVariant()
2339 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2341 MyQmlContainer container;
2343 QDeclarativeContext context(engine.rootContext());
2344 context.setContextObject(&container);
2346 QObject *object = component.create(&context);
2347 QVERIFY(object != 0);
2349 QVariant v = object->property("test");
2350 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2351 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2357 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2358 void tst_qdeclarativeecmascript::listAssignment()
2360 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2361 QObject *obj = component.create();
2362 QCOMPARE(obj->property("list1length").toInt(), 2);
2363 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2364 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2365 QCOMPARE(list1.count(&list1), list2.count(&list2));
2366 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2367 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2372 void tst_qdeclarativeecmascript::multiEngineObject()
2375 obj.setStringProperty("Howdy planet");
2377 QDeclarativeEngine e1;
2378 e1.rootContext()->setContextProperty("thing", &obj);
2379 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2381 QDeclarativeEngine e2;
2382 e2.rootContext()->setContextProperty("thing", &obj);
2383 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2385 QObject *o1 = c1.create();
2386 QObject *o2 = c2.create();
2388 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2389 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2395 // Test that references to QObjects are cleanup when the object is destroyed
2396 void tst_qdeclarativeecmascript::deletedObject()
2398 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2400 QObject *object = component.create();
2402 QCOMPARE(object->property("test1").toBool(), true);
2403 QCOMPARE(object->property("test2").toBool(), true);
2404 QCOMPARE(object->property("test3").toBool(), true);
2405 QCOMPARE(object->property("test4").toBool(), true);
2410 void tst_qdeclarativeecmascript::attachedPropertyScope()
2412 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2414 QObject *object = component.create();
2415 QVERIFY(object != 0);
2417 MyQmlAttachedObject *attached =
2418 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2419 QVERIFY(attached != 0);
2421 QCOMPARE(object->property("value2").toInt(), 0);
2423 attached->emitMySignal();
2425 QCOMPARE(object->property("value2").toInt(), 9);
2430 void tst_qdeclarativeecmascript::scriptConnect()
2433 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2435 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2436 QVERIFY(object != 0);
2438 QCOMPARE(object->property("test").toBool(), false);
2439 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2440 QCOMPARE(object->property("test").toBool(), true);
2446 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2448 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2449 QVERIFY(object != 0);
2451 QCOMPARE(object->property("test").toBool(), false);
2452 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2453 QCOMPARE(object->property("test").toBool(), true);
2459 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2461 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2462 QVERIFY(object != 0);
2464 QCOMPARE(object->property("test").toBool(), false);
2465 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2466 QCOMPARE(object->property("test").toBool(), true);
2472 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2474 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2475 QVERIFY(object != 0);
2477 QCOMPARE(object->methodCalled(), false);
2478 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2479 QCOMPARE(object->methodCalled(), true);
2485 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2487 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2488 QVERIFY(object != 0);
2490 QCOMPARE(object->methodCalled(), false);
2491 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2492 QCOMPARE(object->methodCalled(), true);
2498 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2500 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2501 QVERIFY(object != 0);
2503 QCOMPARE(object->property("test").toInt(), 0);
2504 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2505 QCOMPARE(object->property("test").toInt(), 2);
2511 void tst_qdeclarativeecmascript::scriptDisconnect()
2514 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2516 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2517 QVERIFY(object != 0);
2519 QCOMPARE(object->property("test").toInt(), 0);
2520 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2521 QCOMPARE(object->property("test").toInt(), 1);
2522 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2523 QCOMPARE(object->property("test").toInt(), 2);
2524 emit object->basicSignal();
2525 QCOMPARE(object->property("test").toInt(), 2);
2526 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2527 QCOMPARE(object->property("test").toInt(), 2);
2533 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2535 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2536 QVERIFY(object != 0);
2538 QCOMPARE(object->property("test").toInt(), 0);
2539 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2540 QCOMPARE(object->property("test").toInt(), 1);
2541 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2542 QCOMPARE(object->property("test").toInt(), 2);
2543 emit object->basicSignal();
2544 QCOMPARE(object->property("test").toInt(), 2);
2545 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2546 QCOMPARE(object->property("test").toInt(), 2);
2552 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2554 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2555 QVERIFY(object != 0);
2557 QCOMPARE(object->property("test").toInt(), 0);
2558 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2559 QCOMPARE(object->property("test").toInt(), 1);
2560 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2561 QCOMPARE(object->property("test").toInt(), 2);
2562 emit object->basicSignal();
2563 QCOMPARE(object->property("test").toInt(), 2);
2564 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2565 QCOMPARE(object->property("test").toInt(), 3);
2570 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2572 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2573 QVERIFY(object != 0);
2575 QCOMPARE(object->property("test").toInt(), 0);
2576 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2577 QCOMPARE(object->property("test").toInt(), 1);
2578 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2579 QCOMPARE(object->property("test").toInt(), 2);
2580 emit object->basicSignal();
2581 QCOMPARE(object->property("test").toInt(), 2);
2582 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2583 QCOMPARE(object->property("test").toInt(), 3);
2589 class OwnershipObject : public QObject
2593 OwnershipObject() { object = new QObject; }
2595 QPointer<QObject> object;
2598 QObject *getObject() { return object; }
2601 void tst_qdeclarativeecmascript::ownership()
2603 OwnershipObject own;
2604 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2605 context->setContextObject(&own);
2608 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2610 QVERIFY(own.object != 0);
2612 QObject *object = component.create(context);
2614 engine.collectGarbage();
2616 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2618 QVERIFY(own.object == 0);
2623 own.object = new QObject(&own);
2626 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2628 QVERIFY(own.object != 0);
2630 QObject *object = component.create(context);
2632 engine.collectGarbage();
2634 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2636 QVERIFY(own.object != 0);
2644 class CppOwnershipReturnValue : public QObject
2648 CppOwnershipReturnValue() : value(0) {}
2649 ~CppOwnershipReturnValue() { delete value; }
2651 Q_INVOKABLE QObject *create() {
2652 value = new QObject;
2653 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2657 Q_INVOKABLE MyQmlObject *createQmlObject() {
2658 MyQmlObject *rv = new MyQmlObject;
2663 QPointer<QObject> value;
2667 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2668 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2670 CppOwnershipReturnValue source;
2673 QDeclarativeEngine engine;
2674 engine.rootContext()->setContextProperty("source", &source);
2676 QVERIFY(source.value == 0);
2678 QDeclarativeComponent component(&engine);
2679 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2681 QObject *object = component.create();
2683 QVERIFY(object != 0);
2684 QVERIFY(source.value != 0);
2689 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2691 QVERIFY(source.value != 0);
2695 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2697 CppOwnershipReturnValue source;
2700 QDeclarativeEngine engine;
2701 engine.rootContext()->setContextProperty("source", &source);
2703 QVERIFY(source.value == 0);
2705 QDeclarativeComponent component(&engine);
2706 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2708 QObject *object = component.create();
2710 QVERIFY(object != 0);
2711 QVERIFY(source.value != 0);
2716 engine.collectGarbage();
2717 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2719 QVERIFY(source.value == 0);
2722 class QListQObjectMethodsObject : public QObject
2726 QListQObjectMethodsObject() {
2727 m_objects.append(new MyQmlObject());
2728 m_objects.append(new MyQmlObject());
2731 ~QListQObjectMethodsObject() {
2732 qDeleteAll(m_objects);
2736 QList<QObject *> getObjects() { return m_objects; }
2739 QList<QObject *> m_objects;
2742 // Tests that returning a QList<QObject*> from a method works
2743 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2745 QListQObjectMethodsObject obj;
2746 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2747 context->setContextObject(&obj);
2749 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2751 QObject *object = component.create(context);
2753 QCOMPARE(object->property("test").toInt(), 2);
2754 QCOMPARE(object->property("test2").toBool(), true);
2761 void tst_qdeclarativeecmascript::strictlyEquals()
2763 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2765 QObject *object = component.create();
2766 QVERIFY(object != 0);
2768 QCOMPARE(object->property("test1").toBool(), true);
2769 QCOMPARE(object->property("test2").toBool(), true);
2770 QCOMPARE(object->property("test3").toBool(), true);
2771 QCOMPARE(object->property("test4").toBool(), true);
2772 QCOMPARE(object->property("test5").toBool(), true);
2773 QCOMPARE(object->property("test6").toBool(), true);
2774 QCOMPARE(object->property("test7").toBool(), true);
2775 QCOMPARE(object->property("test8").toBool(), true);
2780 void tst_qdeclarativeecmascript::compiled()
2782 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2784 QObject *object = component.create();
2785 QVERIFY(object != 0);
2787 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2788 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2789 QCOMPARE(object->property("test3").toBool(), true);
2790 QCOMPARE(object->property("test4").toBool(), false);
2791 QCOMPARE(object->property("test5").toBool(), false);
2792 QCOMPARE(object->property("test6").toBool(), true);
2794 QCOMPARE(object->property("test7").toInt(), 185);
2795 QCOMPARE(object->property("test8").toInt(), 167);
2796 QCOMPARE(object->property("test9").toBool(), true);
2797 QCOMPARE(object->property("test10").toBool(), false);
2798 QCOMPARE(object->property("test11").toBool(), false);
2799 QCOMPARE(object->property("test12").toBool(), true);
2801 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2802 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2803 QCOMPARE(object->property("test15").toBool(), false);
2804 QCOMPARE(object->property("test16").toBool(), true);
2806 QCOMPARE(object->property("test17").toInt(), 5);
2807 QCOMPARE(object->property("test18").toReal(), qreal(176));
2808 QCOMPARE(object->property("test19").toInt(), 7);
2809 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2810 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2811 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2812 QCOMPARE(object->property("test23").toBool(), true);
2813 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2814 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2819 // Test that numbers assigned in bindings as strings work consistently
2820 void tst_qdeclarativeecmascript::numberAssignment()
2822 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2824 QObject *object = component.create();
2825 QVERIFY(object != 0);
2827 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2828 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2829 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2830 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2831 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2833 QCOMPARE(object->property("test5"), QVariant((int)7));
2834 QCOMPARE(object->property("test6"), QVariant((int)7));
2835 QCOMPARE(object->property("test7"), QVariant((int)6));
2836 QCOMPARE(object->property("test8"), QVariant((int)6));
2838 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2839 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2840 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2841 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2846 void tst_qdeclarativeecmascript::propertySplicing()
2848 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2850 QObject *object = component.create();
2851 QVERIFY(object != 0);
2853 QCOMPARE(object->property("test").toBool(), true);
2859 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2861 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2863 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2864 QVERIFY(object != 0);
2866 MyQmlObject::MyType type;
2867 type.value = 0x8971123;
2868 emit object->signalWithUnknownType(type);
2870 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2872 QCOMPARE(result.value, type.value);
2878 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2880 QTest::addColumn<QString>("expression");
2881 QTest::addColumn<QString>("compare");
2883 QString compareStrict("(function(a, b) { return a === b; })");
2884 QTest::newRow("true") << "true" << compareStrict;
2885 QTest::newRow("undefined") << "undefined" << compareStrict;
2886 QTest::newRow("null") << "null" << compareStrict;
2887 QTest::newRow("123") << "123" << compareStrict;
2888 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2890 QString comparePropertiesStrict(
2892 " if (typeof b != 'object')"
2894 " var props = Object.getOwnPropertyNames(b);"
2895 " for (var i = 0; i < props.length; ++i) {"
2896 " var p = props[i];"
2897 " return arguments.callee(a[p], b[p]);"
2900 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2901 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2904 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2906 QFETCH(QString, expression);
2907 QFETCH(QString, compare);
2909 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2910 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2911 QVERIFY(object != 0);
2913 QJSValue value = engine.evaluate(expression);
2914 QVERIFY(!engine.hasUncaughtException());
2915 object->setProperty("expression", expression);
2916 object->setProperty("compare", compare);
2917 object->setProperty("pass", false);
2919 emit object->signalWithVariant(QVariant::fromValue(value));
2920 QVERIFY(object->property("pass").toBool());
2923 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2925 signalWithJSValueInVariant_data();
2928 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2930 QFETCH(QString, expression);
2931 QFETCH(QString, compare);
2933 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2934 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2935 QVERIFY(object != 0);
2938 QJSValue value = engine2.evaluate(expression);
2939 QVERIFY(!engine2.hasUncaughtException());
2940 object->setProperty("expression", expression);
2941 object->setProperty("compare", compare);
2942 object->setProperty("pass", false);
2944 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2945 emit object->signalWithVariant(QVariant::fromValue(value));
2946 QVERIFY(!object->property("pass").toBool());
2949 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2951 signalWithJSValueInVariant_data();
2954 void tst_qdeclarativeecmascript::signalWithQJSValue()
2956 QFETCH(QString, expression);
2957 QFETCH(QString, compare);
2959 QDeclarativeComponent component(&engine, TEST_FILE("signalWithQJSValue.qml"));
2960 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2961 QVERIFY(object != 0);
2963 QJSValue value = engine.evaluate(expression);
2964 QVERIFY(!engine.hasUncaughtException());
2965 object->setProperty("expression", expression);
2966 object->setProperty("compare", compare);
2967 object->setProperty("pass", false);
2969 emit object->signalWithQJSValue(value);
2971 QVERIFY(object->property("pass").toBool());
2972 QVERIFY(object->qjsvalue().strictlyEquals(value));
2975 void tst_qdeclarativeecmascript::moduleApi_data()
2977 QTest::addColumn<QUrl>("testfile");
2978 QTest::addColumn<QString>("errorMessage");
2979 QTest::addColumn<QStringList>("warningMessages");
2980 QTest::addColumn<QStringList>("readProperties");
2981 QTest::addColumn<QVariantList>("readExpectedValues");
2982 QTest::addColumn<QStringList>("writeProperties");
2983 QTest::addColumn<QVariantList>("writeValues");
2984 QTest::addColumn<QStringList>("readBackProperties");
2985 QTest::addColumn<QVariantList>("readBackExpectedValues");
2987 QTest::newRow("qobject, register + read + method")
2988 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2991 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2992 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2993 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2999 QTest::newRow("script, register + read")
3000 << TEST_FILE("moduleapi/scriptModuleApi.qml")
3003 << (QStringList() << "scriptTest")
3004 << (QVariantList() << 13)
3010 QTest::newRow("qobject, caching + read")
3011 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
3014 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3015 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3021 QTest::newRow("script, caching + read")
3022 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
3025 << (QStringList() << "scriptTest")
3026 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3032 QTest::newRow("qobject, writing + readonly constraints")
3033 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
3035 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3036 << (QStringList() << "readOnlyProperty" << "writableProperty")
3037 << (QVariantList() << 20 << 50)
3038 << (QStringList() << "firstProperty" << "writableProperty")
3039 << (QVariantList() << 30 << 30)
3040 << (QStringList() << "readOnlyProperty" << "writableProperty")
3041 << (QVariantList() << 20 << 30);
3043 QTest::newRow("script, writing + readonly constraints")
3044 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
3046 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3047 << (QStringList() << "readBack" << "unchanged")
3048 << (QVariantList() << 13 << 42)
3049 << (QStringList() << "firstProperty" << "secondProperty")
3050 << (QVariantList() << 30 << 30)
3051 << (QStringList() << "readBack" << "unchanged")
3052 << (QVariantList() << 30 << 42);
3054 QTest::newRow("qobject module API enum values in JS")
3055 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3058 << (QStringList() << "enumValue" << "enumMethod")
3059 << (QVariantList() << 42 << 30)
3065 QTest::newRow("qobject, invalid major version fail")
3066 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3067 << QString("QDeclarativeComponent: Component is not ready")
3076 QTest::newRow("qobject, invalid minor version fail")
3077 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3078 << QString("QDeclarativeComponent: Component is not ready")
3088 void tst_qdeclarativeecmascript::moduleApi()
3090 QFETCH(QUrl, testfile);
3091 QFETCH(QString, errorMessage);
3092 QFETCH(QStringList, warningMessages);
3093 QFETCH(QStringList, readProperties);
3094 QFETCH(QVariantList, readExpectedValues);
3095 QFETCH(QStringList, writeProperties);
3096 QFETCH(QVariantList, writeValues);
3097 QFETCH(QStringList, readBackProperties);
3098 QFETCH(QVariantList, readBackExpectedValues);
3100 QDeclarativeComponent component(&engine, testfile);
3102 if (!errorMessage.isEmpty())
3103 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3105 if (warningMessages.size())
3106 foreach (const QString &warning, warningMessages)
3107 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3109 QObject *object = component.create();
3110 if (!errorMessage.isEmpty()) {
3111 QVERIFY(object == 0);
3113 QVERIFY(object != 0);
3114 for (int i = 0; i < readProperties.size(); ++i)
3115 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3116 for (int i = 0; i < writeProperties.size(); ++i)
3117 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3118 for (int i = 0; i < readBackProperties.size(); ++i)
3119 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3124 void tst_qdeclarativeecmascript::importScripts_data()
3126 QTest::addColumn<QUrl>("testfile");
3127 QTest::addColumn<QString>("errorMessage");
3128 QTest::addColumn<QStringList>("warningMessages");
3129 QTest::addColumn<QStringList>("propertyNames");
3130 QTest::addColumn<QVariantList>("propertyValues");
3132 QTest::newRow("basic functionality")
3133 << TEST_FILE("jsimport/testImport.qml")
3136 << (QStringList() << QLatin1String("importedScriptStringValue")
3137 << QLatin1String("importedScriptFunctionValue")
3138 << QLatin1String("importedModuleAttachedPropertyValue")
3139 << QLatin1String("importedModuleEnumValue"))
3140 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3145 QTest::newRow("import scoping")
3146 << TEST_FILE("jsimport/testImportScoping.qml")
3149 << (QStringList() << QLatin1String("componentError"))
3150 << (QVariantList() << QVariant(5));
3152 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3153 << TEST_FILE("jsimportfail/failOne.qml")
3155 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3156 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3157 << (QVariantList() << QVariant(QString()));
3159 QTest::newRow("javascript imports in an import should be private to the import scope")
3160 << TEST_FILE("jsimportfail/failTwo.qml")
3162 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3163 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3164 << (QVariantList() << QVariant(QString()));
3166 QTest::newRow("module imports in an import should be private to the import scope")
3167 << TEST_FILE("jsimportfail/failThree.qml")
3169 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3170 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3171 << (QVariantList() << QVariant(false));
3173 QTest::newRow("typenames in an import should be private to the import scope")
3174 << TEST_FILE("jsimportfail/failFour.qml")
3176 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3177 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3178 << (QVariantList() << QVariant(0));
3180 QTest::newRow("import with imports has it's own activation scope")
3181 << TEST_FILE("jsimportfail/failFive.qml")
3183 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3184 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3185 << (QStringList() << QLatin1String("componentError"))
3186 << (QVariantList() << QVariant(0));
3188 QTest::newRow("import pragma library script")
3189 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3192 << (QStringList() << QLatin1String("testValue"))
3193 << (QVariantList() << QVariant(31));
3195 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3196 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3199 << (QStringList() << QLatin1String("testValue"))
3200 << (QVariantList() << QVariant(0));
3202 QTest::newRow("import pragma library script which has an import")
3203 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3206 << (QStringList() << QLatin1String("testValue"))
3207 << (QVariantList() << QVariant(55));
3209 QTest::newRow("import pragma library script which has a pragma library import")
3210 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3213 << (QStringList() << QLatin1String("testValue"))
3214 << (QVariantList() << QVariant(18));
3217 void tst_qdeclarativeecmascript::importScripts()
3219 QFETCH(QUrl, testfile);
3220 QFETCH(QString, errorMessage);
3221 QFETCH(QStringList, warningMessages);
3222 QFETCH(QStringList, propertyNames);
3223 QFETCH(QVariantList, propertyValues);
3225 QDeclarativeComponent component(&engine, testfile);
3227 if (!errorMessage.isEmpty())
3228 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3230 if (warningMessages.size())
3231 foreach (const QString &warning, warningMessages)
3232 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3234 QObject *object = component.create();
3235 if (!errorMessage.isEmpty()) {
3236 QVERIFY(object == 0);
3238 QVERIFY(object != 0);
3239 for (int i = 0; i < propertyNames.size(); ++i)
3240 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3245 void tst_qdeclarativeecmascript::scarceResources_other()
3247 /* These tests require knowledge of state, since we test values after
3248 performing signal or function invocation. */
3250 QPixmap origPixmap(100, 100);
3251 origPixmap.fill(Qt::blue);
3252 QString srp_name, expectedWarning;
3253 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3254 ScarceResourceObject *eo = 0;
3256 QObject *object = 0;
3258 /* property var semantics */
3260 // test that scarce resources are handled properly in signal invocation
3261 QDeclarativeComponent varComponentTen(&engine, TEST_FILE("scarceResourceSignal.var.qml"));
3262 object = varComponentTen.create();
3263 srsc = object->findChild<QObject*>("srsc");
3265 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3266 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3267 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3268 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3269 QMetaObject::invokeMethod(srsc, "testSignal");
3270 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3271 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3272 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3273 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3274 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3275 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3276 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3277 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3278 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3279 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3282 // test that scarce resources are handled properly from js functions in qml files
3283 QDeclarativeComponent varComponentEleven(&engine, TEST_FILE("scarceResourceFunction.var.qml"));
3284 object = varComponentEleven.create();
3285 QVERIFY(object != 0);
3286 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3287 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3288 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3289 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3290 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3291 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3292 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3293 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3294 QMetaObject::invokeMethod(object, "releaseScarceResource");
3295 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3296 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3297 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3298 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3301 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3302 QDeclarativeComponent varComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
3303 object = varComponentTwelve.create();
3304 QVERIFY(object != 0);
3305 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3306 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3307 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3308 srp_name = object->property("srp_name").toString();
3309 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3310 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3311 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3312 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3313 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3314 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3315 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3318 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3319 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3320 QDeclarativeComponent varComponentThirteen(&engine, TEST_FILE("scarceResourceObjectGc.var.qml"));
3321 object = varComponentThirteen.create();
3322 QVERIFY(object != 0);
3323 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3324 QMetaObject::invokeMethod(object, "assignVarProperty");
3325 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3326 QMetaObject::invokeMethod(object, "deassignVarProperty");
3327 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3330 /* property variant semantics */
3332 // test that scarce resources are handled properly in signal invocation
3333 QDeclarativeComponent variantComponentTen(&engine, TEST_FILE("scarceResourceSignal.variant.qml"));
3334 object = variantComponentTen.create();
3335 QVERIFY(object != 0);
3336 srsc = object->findChild<QObject*>("srsc");
3338 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3339 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3340 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3341 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3342 QMetaObject::invokeMethod(srsc, "testSignal");
3343 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3344 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3345 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3346 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3347 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3348 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3349 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3350 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3351 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3352 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3355 // test that scarce resources are handled properly from js functions in qml files
3356 QDeclarativeComponent variantComponentEleven(&engine, TEST_FILE("scarceResourceFunction.variant.qml"));
3357 object = variantComponentEleven.create();
3358 QVERIFY(object != 0);
3359 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3360 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3361 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3362 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3363 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3364 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3365 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3366 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3367 QMetaObject::invokeMethod(object, "releaseScarceResource");
3368 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3369 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3370 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3371 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3374 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3375 QDeclarativeComponent variantComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.variant.qml"));
3376 object = variantComponentTwelve.create();
3377 QVERIFY(object != 0);
3378 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3379 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3380 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3381 srp_name = object->property("srp_name").toString();
3382 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3383 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3384 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3385 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3386 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3387 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3388 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3392 void tst_qdeclarativeecmascript::scarceResources_data()
3394 QTest::addColumn<QUrl>("qmlFile");
3395 QTest::addColumn<bool>("readDetachStatus");
3396 QTest::addColumn<bool>("expectedDetachStatus");
3397 QTest::addColumn<QStringList>("propertyNames");
3398 QTest::addColumn<QVariantList>("expectedValidity");
3399 QTest::addColumn<QVariantList>("expectedValues");
3400 QTest::addColumn<QStringList>("expectedErrors");
3402 QPixmap origPixmap(100, 100);
3403 origPixmap.fill(Qt::blue);
3405 /* property var semantics */
3407 // in the following three cases, the instance created from the component
3408 // has a property which is a copy of the scarce resource; hence, the
3409 // resource should NOT be detached prior to deletion of the object instance,
3410 // unless the resource is destroyed explicitly.
3411 QTest::newRow("var: import scarce resource copy directly")
3412 << TEST_FILE("scarceResourceCopy.var.qml")
3414 << false // won't be detached, because assigned to property and not explicitly released
3415 << (QStringList() << QLatin1String("scarceResourceCopy"))
3416 << (QList<QVariant>() << true)
3417 << (QList<QVariant>() << origPixmap)
3420 QTest::newRow("var: import scarce resource copy from JS")
3421 << TEST_FILE("scarceResourceCopyFromJs.var.qml")
3423 << false // won't be detached, because assigned to property and not explicitly released
3424 << (QStringList() << QLatin1String("scarceResourceCopy"))
3425 << (QList<QVariant>() << true)
3426 << (QList<QVariant>() << origPixmap)
3429 QTest::newRow("var: import released scarce resource copy from JS")
3430 << TEST_FILE("scarceResourceDestroyedCopy.var.qml")
3432 << true // explicitly released, so it will be detached
3433 << (QStringList() << QLatin1String("scarceResourceCopy"))
3434 << (QList<QVariant>() << false)
3435 << (QList<QVariant>() << QVariant())
3438 // in the following three cases, no other copy should exist in memory,
3439 // and so it should be detached (unless explicitly preserved).
3440 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3441 << TEST_FILE("scarceResourceTest.var.qml")
3443 << true // auto released, so it will be detached
3444 << (QStringList() << QLatin1String("scarceResourceTest"))
3445 << (QList<QVariant>() << true)
3446 << (QList<QVariant>() << QVariant(100))
3448 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3449 << TEST_FILE("scarceResourceTestPreserve.var.qml")
3451 << false // won't be detached because we explicitly preserve it
3452 << (QStringList() << QLatin1String("scarceResourceTest"))
3453 << (QList<QVariant>() << true)
3454 << (QList<QVariant>() << QVariant(100))
3456 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3457 << TEST_FILE("scarceResourceTestMultiple.var.qml")
3459 << true // will be detached because all resources were released manually or automatically.
3460 << (QStringList() << QLatin1String("scarceResourceTest"))
3461 << (QList<QVariant>() << true)
3462 << (QList<QVariant>() << QVariant(100))
3465 // In the following three cases, test that scarce resources are handled
3466 // correctly for imports.
3467 QTest::newRow("var: import with no binding")
3468 << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
3469 << false // cannot check detach status.
3472 << QList<QVariant>()
3473 << QList<QVariant>()
3475 QTest::newRow("var: import with binding without explicit preserve")
3476 << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
3479 << (QStringList() << QLatin1String("scarceResourceCopy"))
3480 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3481 << (QList<QVariant>() << QVariant())
3483 QTest::newRow("var: import with explicit release after binding evaluation")
3484 << TEST_FILE("scarceResourceCopyImport.var.qml")
3487 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3488 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3489 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3491 QTest::newRow("var: import with different js objects")
3492 << TEST_FILE("scarceResourceCopyImportDifferent.var.qml")
3495 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3496 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3497 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3499 QTest::newRow("var: import with different js objects and explicit release")
3500 << TEST_FILE("scarceResourceMultipleDifferentNoBinding.var.qml")
3503 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3504 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3505 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3507 QTest::newRow("var: import with same js objects and explicit release")
3508 << TEST_FILE("scarceResourceMultipleSameNoBinding.var.qml")
3511 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3512 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3513 << (QList<QVariant>() << QVariant() << QVariant())
3515 QTest::newRow("var: binding with same js objects and explicit release")
3516 << TEST_FILE("scarceResourceMultipleSameWithBinding.var.qml")
3519 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3520 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3521 << (QList<QVariant>() << QVariant() << QVariant())
3525 /* property variant semantics */
3527 // in the following three cases, the instance created from the component
3528 // has a property which is a copy of the scarce resource; hence, the
3529 // resource should NOT be detached prior to deletion of the object instance,
3530 // unless the resource is destroyed explicitly.
3531 QTest::newRow("variant: import scarce resource copy directly")
3532 << TEST_FILE("scarceResourceCopy.variant.qml")
3534 << false // won't be detached, because assigned to property and not explicitly released
3535 << (QStringList() << QLatin1String("scarceResourceCopy"))
3536 << (QList<QVariant>() << true)
3537 << (QList<QVariant>() << origPixmap)
3540 QTest::newRow("variant: import scarce resource copy from JS")
3541 << TEST_FILE("scarceResourceCopyFromJs.variant.qml")
3543 << false // won't be detached, because assigned to property and not explicitly released
3544 << (QStringList() << QLatin1String("scarceResourceCopy"))
3545 << (QList<QVariant>() << true)
3546 << (QList<QVariant>() << origPixmap)
3549 QTest::newRow("variant: import released scarce resource copy from JS")
3550 << TEST_FILE("scarceResourceDestroyedCopy.variant.qml")
3552 << true // explicitly released, so it will be detached
3553 << (QStringList() << QLatin1String("scarceResourceCopy"))
3554 << (QList<QVariant>() << false)
3555 << (QList<QVariant>() << QVariant())
3558 // in the following three cases, no other copy should exist in memory,
3559 // and so it should be detached (unless explicitly preserved).
3560 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3561 << TEST_FILE("scarceResourceTest.variant.qml")
3563 << true // auto released, so it will be detached
3564 << (QStringList() << QLatin1String("scarceResourceTest"))
3565 << (QList<QVariant>() << true)
3566 << (QList<QVariant>() << QVariant(100))
3568 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3569 << TEST_FILE("scarceResourceTestPreserve.variant.qml")
3571 << false // won't be detached because we explicitly preserve it
3572 << (QStringList() << QLatin1String("scarceResourceTest"))
3573 << (QList<QVariant>() << true)
3574 << (QList<QVariant>() << QVariant(100))
3576 QTest::newRow("variant: import multiple scarce resources")
3577 << TEST_FILE("scarceResourceTestMultiple.variant.qml")
3579 << true // will be detached because all resources were released manually or automatically.
3580 << (QStringList() << QLatin1String("scarceResourceTest"))
3581 << (QList<QVariant>() << true)
3582 << (QList<QVariant>() << QVariant(100))
3585 // In the following three cases, test that scarce resources are handled
3586 // correctly for imports.
3587 QTest::newRow("variant: import with no binding")
3588 << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
3589 << false // cannot check detach status.
3592 << QList<QVariant>()
3593 << QList<QVariant>()
3595 QTest::newRow("variant: import with binding without explicit preserve")
3596 << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
3599 << (QStringList() << QLatin1String("scarceResourceCopy"))
3600 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3601 << (QList<QVariant>() << QVariant())
3603 QTest::newRow("variant: import with explicit release after binding evaluation")
3604 << TEST_FILE("scarceResourceCopyImport.variant.qml")
3607 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3608 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3609 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3613 void tst_qdeclarativeecmascript::scarceResources()
3615 QFETCH(QUrl, qmlFile);
3616 QFETCH(bool, readDetachStatus);
3617 QFETCH(bool, expectedDetachStatus);
3618 QFETCH(QStringList, propertyNames);
3619 QFETCH(QVariantList, expectedValidity);
3620 QFETCH(QVariantList, expectedValues);
3621 QFETCH(QStringList, expectedErrors);
3623 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3624 ScarceResourceObject *eo = 0;
3625 QObject *object = 0;
3627 QDeclarativeComponent c(&engine, qmlFile);
3628 object = c.create();
3629 QVERIFY(object != 0);
3630 for (int i = 0; i < propertyNames.size(); ++i) {
3631 QString prop = propertyNames.at(i);
3632 bool validity = expectedValidity.at(i).toBool();
3633 QVariant value = expectedValues.at(i);
3635 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3636 if (value.type() == QVariant::Int) {
3637 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3638 } else if (value.type() == QVariant::Pixmap) {
3639 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3643 if (readDetachStatus) {
3644 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3645 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3648 QVERIFY(ep->scarceResources.isEmpty());
3652 void tst_qdeclarativeecmascript::propertyChangeSlots()
3654 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3655 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3656 QObject *object = component.create();
3657 QVERIFY(object != 0);
3660 // ensure that invalid property names fail properly.
3661 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3662 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3663 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3664 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3665 object = e1.create();
3666 QVERIFY(object == 0);
3669 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3670 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3671 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3672 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3673 object = e2.create();
3674 QVERIFY(object == 0);
3677 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3678 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3679 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3680 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3681 object = e3.create();
3682 QVERIFY(object == 0);
3685 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3686 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3687 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3688 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3689 object = e4.create();
3690 QVERIFY(object == 0);
3694 void tst_qdeclarativeecmascript::propertyVar_data()
3696 QTest::addColumn<QUrl>("qmlFile");
3699 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3700 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3701 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3702 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3703 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3704 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3705 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3706 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3707 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3710 void tst_qdeclarativeecmascript::propertyVar()
3712 QFETCH(QUrl, qmlFile);
3714 QDeclarativeComponent component(&engine, qmlFile);
3715 QObject *object = component.create();
3716 QVERIFY(object != 0);
3718 QCOMPARE(object->property("test").toBool(), true);
3723 // Tests that we can write QVariant values to var properties from C++
3724 void tst_qdeclarativeecmascript::propertyVarCpp()
3726 QObject *object = 0;
3728 // ensure that writing to and reading from a var property from cpp works as required.
3729 // Literal values stored in var properties can be read and written as QVariants
3730 // of a specific type, whereas object values are read as QVariantMaps.
3731 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3732 object = component.create();
3733 QVERIFY(object != 0);
3734 // assign int to property var that currently has int assigned
3735 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3736 QCOMPARE(object->property("varBound"), QVariant(15));
3737 QCOMPARE(object->property("intBound"), QVariant(15));
3738 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3739 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3740 // assign string to property var that current has bool assigned
3741 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3742 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3743 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3744 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3745 // now enforce behaviour when accessing JavaScript objects from cpp.
3746 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3750 static void gc(QDeclarativeEngine &engine)
3752 engine.collectGarbage();
3753 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3756 void tst_qdeclarativeecmascript::propertyVarOwnership()
3758 // Referenced JS objects are not collected
3760 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3761 QObject *object = component.create();
3762 QVERIFY(object != 0);
3763 QCOMPARE(object->property("test").toBool(), false);
3764 QMetaObject::invokeMethod(object, "runTest");
3765 QCOMPARE(object->property("test").toBool(), true);
3768 // Referenced JS objects are not collected
3770 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3771 QObject *object = component.create();
3772 QVERIFY(object != 0);
3773 QCOMPARE(object->property("test").toBool(), false);
3774 QMetaObject::invokeMethod(object, "runTest");
3775 QCOMPARE(object->property("test").toBool(), true);
3778 // Qt objects are not collected until they've been dereferenced
3780 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3781 QObject *object = component.create();
3782 QVERIFY(object != 0);
3784 QCOMPARE(object->property("test2").toBool(), false);
3785 QCOMPARE(object->property("test2").toBool(), false);
3787 QMetaObject::invokeMethod(object, "runTest");
3788 QCOMPARE(object->property("test1").toBool(), true);
3790 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3791 QVERIFY(!referencedObject.isNull());
3793 QVERIFY(!referencedObject.isNull());
3795 QMetaObject::invokeMethod(object, "runTest2");
3796 QCOMPARE(object->property("test2").toBool(), true);
3798 QVERIFY(referencedObject.isNull());
3802 // Self reference does not prevent Qt object collection
3804 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3805 QObject *object = component.create();
3806 QVERIFY(object != 0);
3808 QCOMPARE(object->property("test").toBool(), true);
3810 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3811 QVERIFY(!referencedObject.isNull());
3813 QVERIFY(!referencedObject.isNull());
3815 QMetaObject::invokeMethod(object, "runTest");
3817 QVERIFY(referencedObject.isNull());
3823 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3825 // The childObject has a reference to a different QObject. We want to ensure
3826 // that the different item will not be cleaned up until required. IE, the childObject
3827 // has implicit ownership of the constructed QObject.
3828 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3829 QObject *object = component.create();
3830 QVERIFY(object != 0);
3831 QMetaObject::invokeMethod(object, "assignCircular");
3832 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3833 QObject *rootObject = object->property("vp").value<QObject*>();
3834 QVERIFY(rootObject != 0);
3835 QObject *childObject = rootObject->findChild<QObject*>("text");
3836 QVERIFY(childObject != 0);
3837 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3838 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3839 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3840 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3841 QVERIFY(!qobjectGuard.isNull());
3842 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3843 QVERIFY(!qobjectGuard.isNull());
3844 QMetaObject::invokeMethod(object, "deassignCircular");
3845 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3846 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3850 void tst_qdeclarativeecmascript::propertyVarReparent()
3852 // ensure that nothing breaks if we re-parent objects
3853 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3854 QObject *object = component.create();
3855 QVERIFY(object != 0);
3856 QMetaObject::invokeMethod(object, "assignVarProp");
3857 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3858 QObject *rect = object->property("vp").value<QObject*>();
3859 QObject *text = rect->findChild<QObject*>("textOne");
3860 QObject *text2 = rect->findChild<QObject*>("textTwo");
3861 QWeakPointer<QObject> rectGuard(rect);
3862 QWeakPointer<QObject> textGuard(text);
3863 QWeakPointer<QObject> text2Guard(text2);
3864 QVERIFY(!rectGuard.isNull());
3865 QVERIFY(!textGuard.isNull());
3866 QVERIFY(!text2Guard.isNull());
3867 QCOMPARE(text->property("textCanary").toInt(), 11);
3868 QCOMPARE(text2->property("textCanary").toInt(), 12);
3869 // now construct an image which we will reparent.
3870 QMetaObject::invokeMethod(text2, "constructQObject");
3871 QObject *image = text2->property("vp").value<QObject*>();
3872 QWeakPointer<QObject> imageGuard(image);
3873 QVERIFY(!imageGuard.isNull());
3874 QCOMPARE(image->property("imageCanary").toInt(), 13);
3875 // now reparent the "Image" object (currently, it has JS ownership)
3876 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3877 QMetaObject::invokeMethod(text2, "deassignVp");
3878 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3879 QCOMPARE(text->property("textCanary").toInt(), 11);
3880 QCOMPARE(text2->property("textCanary").toInt(), 22);
3881 QVERIFY(!imageGuard.isNull()); // should still be alive.
3882 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3883 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3884 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3885 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3889 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3891 // sometimes reparenting can cause problems
3892 // (eg, if the ctxt is collected, varproperties are no longer available)
3893 // this test ensures that no crash occurs in that situation.
3894 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3895 QObject *object = component.create();
3896 QVERIFY(object != 0);
3897 QMetaObject::invokeMethod(object, "assignVarProp");
3898 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3899 QObject *rect = object->property("vp").value<QObject*>();
3900 QObject *text = rect->findChild<QObject*>("textOne");
3901 QObject *text2 = rect->findChild<QObject*>("textTwo");
3902 QWeakPointer<QObject> rectGuard(rect);
3903 QWeakPointer<QObject> textGuard(text);
3904 QWeakPointer<QObject> text2Guard(text2);
3905 QVERIFY(!rectGuard.isNull());
3906 QVERIFY(!textGuard.isNull());
3907 QVERIFY(!text2Guard.isNull());
3908 QCOMPARE(text->property("textCanary").toInt(), 11);
3909 QCOMPARE(text2->property("textCanary").toInt(), 12);
3910 // now construct an image which we will reparent.
3911 QMetaObject::invokeMethod(text2, "constructQObject");
3912 QObject *image = text2->property("vp").value<QObject*>();
3913 QWeakPointer<QObject> imageGuard(image);
3914 QVERIFY(!imageGuard.isNull());
3915 QCOMPARE(image->property("imageCanary").toInt(), 13);
3916 // now reparent the "Image" object (currently, it has JS ownership)
3917 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3918 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3919 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3920 QVERIFY(!imageGuard.isNull()); // should still be alive.
3921 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3923 QVERIFY(imageGuard.isNull()); // should now be dead.
3926 void tst_qdeclarativeecmascript::propertyVarCircular()
3928 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3929 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3930 QObject *object = component.create();
3931 QVERIFY(object != 0);
3932 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3933 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3934 QCOMPARE(object->property("canaryInt"), QVariant(5));
3935 QVariant canaryResourceVariant = object->property("canaryResource");
3936 QVERIFY(canaryResourceVariant.isValid());
3937 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3938 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3939 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3940 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3941 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3942 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3943 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3944 QCOMPARE(object->property("canaryInt"), QVariant(2));
3945 QCOMPARE(object->property("canaryResource"), QVariant(1));
3946 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3950 void tst_qdeclarativeecmascript::propertyVarCircular2()
3952 // track deletion of JS-owned parent item with Cpp-owned child
3953 // where the child has a var property referencing its parent.
3954 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3955 QObject *object = component.create();
3956 QVERIFY(object != 0);
3957 QMetaObject::invokeMethod(object, "assignCircular");
3958 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3959 QObject *rootObject = object->property("vp").value<QObject*>();
3960 QVERIFY(rootObject != 0);
3961 QObject *childObject = rootObject->findChild<QObject*>("text");
3962 QVERIFY(childObject != 0);
3963 QWeakPointer<QObject> rootObjectTracker(rootObject);
3964 QVERIFY(!rootObjectTracker.isNull());
3965 QWeakPointer<QObject> childObjectTracker(childObject);
3966 QVERIFY(!childObjectTracker.isNull());
3968 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3969 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3970 QMetaObject::invokeMethod(object, "deassignCircular");
3971 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3972 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3973 QVERIFY(childObjectTracker.isNull()); // should have been collected
3977 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3979 *(int*)(parameter) += 1;
3980 qPersistentDispose(object);
3983 void tst_qdeclarativeecmascript::propertyVarInheritance()
3985 int propertyVarWeakRefCallbackCount = 0;
3987 // enforce behaviour regarding element inheritance - ensure handle disposal.
3988 // The particular component under test here has a chain of references.
3989 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3990 QObject *object = component.create();
3991 QVERIFY(object != 0);
3992 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3993 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3994 // we want to be able to track when the varProperties array of the last metaobject is disposed
3995 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3996 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*>();
3997 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3998 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3999 v8::Persistent<v8::Value> icoCanaryHandle;
4000 v8::Persistent<v8::Value> ccoCanaryHandle;
4003 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4004 // public function which can return us a handle to something in the varProperties array.
4005 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
4006 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
4007 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4008 // as the varproperties array of each vmemo still references the resource.
4009 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4010 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4012 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4014 // now we deassign the var prop, which should trigger collection of item subtrees.
4015 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4016 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4017 // ensure that there are only weak handles to the underlying varProperties array remaining.
4019 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4021 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4022 // to what remains are weak, all varProperties arrays must have been collected.
4025 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4027 int propertyVarWeakRefCallbackCount = 0;
4029 // The particular component under test here does NOT have a chain of references; the
4030 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4031 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
4032 QObject *object = component.create();
4033 QVERIFY(object != 0);
4034 QMetaObject::invokeMethod(object, "assignCircular");
4035 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4036 QObject *rootObject = object->property("vp").value<QObject*>();
4037 QVERIFY(rootObject != 0);
4038 QObject *childObject = rootObject->findChild<QObject*>("text");
4039 QVERIFY(childObject != 0);
4040 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4041 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4042 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4045 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4046 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
4047 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4049 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4050 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4052 QMetaObject::invokeMethod(object, "deassignCircular");
4053 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4054 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4058 // Ensure that QObject type conversion works on binding assignment
4059 void tst_qdeclarativeecmascript::elementAssign()
4061 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
4063 QObject *object = component.create();
4064 QVERIFY(object != 0);
4066 QCOMPARE(object->property("test").toBool(), true);
4072 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4074 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
4076 QObject *object = component.create();
4077 QVERIFY(object != 0);
4079 QCOMPARE(object->property("test").toBool(), true);
4085 void tst_qdeclarativeecmascript::objectConversion()
4087 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
4089 QObject *object = component.create();
4090 QVERIFY(object != 0);
4092 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4093 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4100 void tst_qdeclarativeecmascript::booleanConversion()
4102 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
4104 QObject *object = component.create();
4105 QVERIFY(object != 0);
4107 QCOMPARE(object->property("test_true1").toBool(), true);
4108 QCOMPARE(object->property("test_true2").toBool(), true);
4109 QCOMPARE(object->property("test_true3").toBool(), true);
4110 QCOMPARE(object->property("test_true4").toBool(), true);
4111 QCOMPARE(object->property("test_true5").toBool(), true);
4113 QCOMPARE(object->property("test_false1").toBool(), false);
4114 QCOMPARE(object->property("test_false2").toBool(), false);
4115 QCOMPARE(object->property("test_false3").toBool(), false);
4120 void tst_qdeclarativeecmascript::handleReferenceManagement()
4125 // Linear QObject reference
4126 QDeclarativeEngine hrmEngine;
4127 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
4128 QObject *object = component.create();
4129 QVERIFY(object != 0);
4130 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4131 cro->setDtorCount(&dtorCount);
4132 QMetaObject::invokeMethod(object, "createReference");
4134 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4136 hrmEngine.collectGarbage();
4137 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4138 QCOMPARE(dtorCount, 3);
4143 // Circular QObject reference
4144 QDeclarativeEngine hrmEngine;
4145 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
4146 QObject *object = component.create();
4147 QVERIFY(object != 0);
4148 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4149 cro->setDtorCount(&dtorCount);
4150 QMetaObject::invokeMethod(object, "circularReference");
4152 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4154 hrmEngine.collectGarbage();
4155 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4156 QCOMPARE(dtorCount, 3);
4161 // Linear handle reference
4162 QDeclarativeEngine hrmEngine;
4163 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4164 QObject *object = component.create();
4165 QVERIFY(object != 0);
4166 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4168 crh->setDtorCount(&dtorCount);
4169 QMetaObject::invokeMethod(object, "createReference");
4170 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4171 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4172 QVERIFY(first != 0);
4173 QVERIFY(second != 0);
4174 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4175 // now we have to reparent second and make second owned by JS.
4176 second->setParent(0);
4177 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4179 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4181 hrmEngine.collectGarbage();
4182 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4183 QCOMPARE(dtorCount, 3);
4188 // Circular handle reference
4189 QDeclarativeEngine hrmEngine;
4190 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
4191 QObject *object = component.create();
4192 QVERIFY(object != 0);
4193 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4195 crh->setDtorCount(&dtorCount);
4196 QMetaObject::invokeMethod(object, "circularReference");
4197 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4198 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4199 QVERIFY(first != 0);
4200 QVERIFY(second != 0);
4201 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4202 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4203 // now we have to reparent and change ownership.
4204 first->setParent(0);
4205 second->setParent(0);
4206 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4207 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4209 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4211 hrmEngine.collectGarbage();
4212 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4213 QCOMPARE(dtorCount, 3);
4218 // multiple engine interaction - linear reference
4219 QDeclarativeEngine hrmEngine1;
4220 QDeclarativeEngine hrmEngine2;
4221 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4222 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4223 QObject *object1 = component1.create();
4224 QObject *object2 = component2.create();
4225 QVERIFY(object1 != 0);
4226 QVERIFY(object2 != 0);
4227 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4228 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4231 crh1->setDtorCount(&dtorCount);
4232 crh2->setDtorCount(&dtorCount);
4233 QMetaObject::invokeMethod(object1, "createReference");
4234 QMetaObject::invokeMethod(object2, "createReference");
4235 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4236 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4237 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4238 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4239 QVERIFY(first1 != 0);
4240 QVERIFY(second1 != 0);
4241 QVERIFY(first2 != 0);
4242 QVERIFY(second2 != 0);
4243 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4244 // now we have to reparent second2 and make second2 owned by JS.
4245 second2->setParent(0);
4246 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4248 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4249 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4252 hrmEngine1.collectGarbage();
4253 hrmEngine2.collectGarbage();
4254 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4255 QCOMPARE(dtorCount, 6);
4260 // multiple engine interaction - circular reference
4261 QDeclarativeEngine hrmEngine1;
4262 QDeclarativeEngine hrmEngine2;
4263 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4264 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4265 QObject *object1 = component1.create();
4266 QObject *object2 = component2.create();
4267 QVERIFY(object1 != 0);
4268 QVERIFY(object2 != 0);
4269 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4270 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4273 crh1->setDtorCount(&dtorCount);
4274 crh2->setDtorCount(&dtorCount);
4275 QMetaObject::invokeMethod(object1, "createReference");
4276 QMetaObject::invokeMethod(object2, "createReference");
4277 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4278 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4279 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4280 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4281 QVERIFY(first1 != 0);
4282 QVERIFY(second1 != 0);
4283 QVERIFY(first2 != 0);
4284 QVERIFY(second2 != 0);
4285 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4286 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4287 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4288 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4289 // now we have to reparent and change ownership to JS.
4290 first1->setParent(0);
4291 second1->setParent(0);
4292 first2->setParent(0);
4293 second2->setParent(0);
4294 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4295 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4296 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4297 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4299 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4300 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4303 hrmEngine1.collectGarbage();
4304 hrmEngine2.collectGarbage();
4305 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4306 QCOMPARE(dtorCount, 6);
4311 // multiple engine interaction - linear reference with engine deletion
4312 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4313 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4314 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4315 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4316 QObject *object1 = component1.create();
4317 QObject *object2 = component2.create();
4318 QVERIFY(object1 != 0);
4319 QVERIFY(object2 != 0);
4320 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4321 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4324 crh1->setDtorCount(&dtorCount);
4325 crh2->setDtorCount(&dtorCount);
4326 QMetaObject::invokeMethod(object1, "createReference");
4327 QMetaObject::invokeMethod(object2, "createReference");
4328 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4329 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4330 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4331 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4332 QVERIFY(first1 != 0);
4333 QVERIFY(second1 != 0);
4334 QVERIFY(first2 != 0);
4335 QVERIFY(second2 != 0);
4336 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4337 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4338 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4339 // now we have to reparent and change ownership to JS.
4340 first1->setParent(crh1);
4341 second1->setParent(0);
4342 first2->setParent(0);
4343 second2->setParent(0);
4344 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4345 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4346 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4348 QCOMPARE(dtorCount, 0);
4351 QCOMPARE(dtorCount, 0);
4354 hrmEngine1->collectGarbage();
4355 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4356 QCOMPARE(dtorCount, 6);
4361 void tst_qdeclarativeecmascript::stringArg()
4363 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4364 QObject *object = component.create();
4365 QVERIFY(object != 0);
4366 QMetaObject::invokeMethod(object, "success");
4367 QVERIFY(object->property("returnValue").toBool());
4369 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4370 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4371 QMetaObject::invokeMethod(object, "failure");
4372 QVERIFY(object->property("returnValue").toBool());
4377 void tst_qdeclarativeecmascript::readonlyDeclaration()
4379 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4381 QObject *object = component.create();
4382 QVERIFY(object != 0);
4384 QCOMPARE(object->property("test").toBool(), true);
4389 Q_DECLARE_METATYPE(QList<int>)
4390 Q_DECLARE_METATYPE(QList<qreal>)
4391 Q_DECLARE_METATYPE(QList<bool>)
4392 Q_DECLARE_METATYPE(QList<QString>)
4393 Q_DECLARE_METATYPE(QList<QUrl>)
4394 void tst_qdeclarativeecmascript::sequenceConversionRead()
4397 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4398 QDeclarativeComponent component(&engine, qmlFile);
4399 QObject *object = component.create();
4400 QVERIFY(object != 0);
4401 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4404 QMetaObject::invokeMethod(object, "readSequences");
4405 QList<int> intList; intList << 1 << 2 << 3 << 4;
4406 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4407 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4408 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4409 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4410 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4411 QList<bool> boolList; boolList << true << false << true << false;
4412 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4413 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4414 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4415 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4416 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4417 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4418 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4419 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4420 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4421 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4422 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4424 QMetaObject::invokeMethod(object, "readSequenceElements");
4425 QCOMPARE(object->property("intVal").toInt(), 2);
4426 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4427 QCOMPARE(object->property("boolVal").toBool(), false);
4428 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4429 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4430 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4432 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4433 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4435 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4436 QDeclarativeProperty seqProp(seq, "intListProperty");
4437 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4438 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4439 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4441 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4442 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4448 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4449 QDeclarativeComponent component(&engine, qmlFile);
4450 QObject *object = component.create();
4451 QVERIFY(object != 0);
4452 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4455 // we haven't registered QList<QPoint> as a sequence type.
4456 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4457 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4458 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4459 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4461 QMetaObject::invokeMethod(object, "performTest");
4463 // QList<QPoint> has not been registered as a sequence type.
4464 QCOMPARE(object->property("pointListLength").toInt(), 0);
4465 QVERIFY(!object->property("pointList").isValid());
4466 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4467 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4468 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4474 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4477 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4478 QDeclarativeComponent component(&engine, qmlFile);
4479 QObject *object = component.create();
4480 QVERIFY(object != 0);
4481 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4484 QMetaObject::invokeMethod(object, "writeSequences");
4485 QCOMPARE(object->property("success").toBool(), true);
4487 QMetaObject::invokeMethod(object, "writeSequenceElements");
4488 QCOMPARE(object->property("success").toBool(), true);
4490 QMetaObject::invokeMethod(object, "writeOtherElements");
4491 QCOMPARE(object->property("success").toBool(), true);
4493 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4494 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4500 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4501 QDeclarativeComponent component(&engine, qmlFile);
4502 QObject *object = component.create();
4503 QVERIFY(object != 0);
4504 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4507 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4508 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4509 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4511 QMetaObject::invokeMethod(object, "performTest");
4513 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4514 QCOMPARE(seq->pointListProperty(), pointList);
4520 void tst_qdeclarativeecmascript::sequenceConversionArray()
4522 // ensure that in JS the returned sequences act just like normal JS Arrays.
4523 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4524 QDeclarativeComponent component(&engine, qmlFile);
4525 QObject *object = component.create();
4526 QVERIFY(object != 0);
4527 QMetaObject::invokeMethod(object, "indexedAccess");
4528 QVERIFY(object->property("success").toBool());
4529 QMetaObject::invokeMethod(object, "arrayOperations");
4530 QVERIFY(object->property("success").toBool());
4531 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4532 QVERIFY(object->property("success").toBool());
4533 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4534 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4538 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4540 // ensure that sequence conversion operations work correctly in a worker thread
4541 // and that serialisation between the main and worker thread succeeds.
4542 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4543 QDeclarativeComponent component(&engine, qmlFile);
4544 QObject *object = component.create();
4545 QVERIFY(object != 0);
4547 QMetaObject::invokeMethod(object, "testIntSequence");
4548 QTRY_VERIFY(object->property("finished").toBool());
4549 QVERIFY(object->property("success").toBool());
4551 QMetaObject::invokeMethod(object, "testQrealSequence");
4552 QTRY_VERIFY(object->property("finished").toBool());
4553 QVERIFY(object->property("success").toBool());
4555 QMetaObject::invokeMethod(object, "testBoolSequence");
4556 QTRY_VERIFY(object->property("finished").toBool());
4557 QVERIFY(object->property("success").toBool());
4559 QMetaObject::invokeMethod(object, "testStringSequence");
4560 QTRY_VERIFY(object->property("finished").toBool());
4561 QVERIFY(object->property("success").toBool());
4563 QMetaObject::invokeMethod(object, "testQStringSequence");
4564 QTRY_VERIFY(object->property("finished").toBool());
4565 QVERIFY(object->property("success").toBool());
4567 QMetaObject::invokeMethod(object, "testUrlSequence");
4568 QTRY_VERIFY(object->property("finished").toBool());
4569 QVERIFY(object->property("success").toBool());
4571 QMetaObject::invokeMethod(object, "testVariantSequence");
4572 QTRY_VERIFY(object->property("finished").toBool());
4573 QVERIFY(object->property("success").toBool());
4578 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4581 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4582 QDeclarativeComponent component(&engine, qmlFile);
4583 QObject *object = component.create();
4584 QVERIFY(object != 0);
4585 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4586 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4587 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4588 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4589 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4594 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4595 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4596 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4597 QDeclarativeComponent component(&engine, qmlFile);
4598 QObject *object = component.create();
4599 QVERIFY(object != 0);
4604 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4606 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4607 QDeclarativeComponent component(&engine, qmlFile);
4608 QObject *object = component.create();
4609 QVERIFY(object != 0);
4610 QMetaObject::invokeMethod(object, "testCopySequences");
4611 QCOMPARE(object->property("success").toBool(), true);
4612 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4613 QCOMPARE(object->property("success").toBool(), true);
4614 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4615 QCOMPARE(object->property("success").toBool(), true);
4619 void tst_qdeclarativeecmascript::assignSequenceTypes()
4621 // test binding array to sequence type property
4623 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.1.qml"));
4624 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4625 QVERIFY(object != 0);
4626 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4627 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4628 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4629 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4630 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4631 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4635 // test binding literal to sequence type property
4637 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.2.qml"));
4638 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4639 QVERIFY(object != 0);
4640 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4641 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4642 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4643 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4644 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4645 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4649 // test binding single value to sequence type property
4651 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.3.qml"));
4652 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4653 QVERIFY(object != 0);
4654 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4655 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4656 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4657 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4661 // test assigning array to sequence type property in js function
4663 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.4.qml"));
4664 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4665 QVERIFY(object != 0);
4666 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4667 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4668 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4669 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4670 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4671 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4675 // test assigning literal to sequence type property in js function
4677 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.5.qml"));
4678 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4679 QVERIFY(object != 0);
4680 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4681 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4682 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4683 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4684 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4685 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4689 // test assigning single value to sequence type property in js function
4691 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.6.qml"));
4692 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4693 QVERIFY(object != 0);
4694 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4695 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4696 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4697 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4702 // Test that assigning a null object works
4703 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4704 void tst_qdeclarativeecmascript::nullObjectBinding()
4706 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4708 QObject *object = component.create();
4709 QVERIFY(object != 0);
4711 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4716 // Test that bindings don't evaluate once the engine has been destroyed
4717 void tst_qdeclarativeecmascript::deletedEngine()
4719 QDeclarativeEngine *engine = new QDeclarativeEngine;
4720 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4722 QObject *object = component.create();
4723 QVERIFY(object != 0);
4725 QCOMPARE(object->property("a").toInt(), 39);
4726 object->setProperty("b", QVariant(9));
4727 QCOMPARE(object->property("a").toInt(), 117);
4731 QCOMPARE(object->property("a").toInt(), 117);
4732 object->setProperty("b", QVariant(10));
4733 QCOMPARE(object->property("a").toInt(), 117);
4738 // Test the crashing part of QTBUG-9705
4739 void tst_qdeclarativeecmascript::libraryScriptAssert()
4741 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4743 QObject *object = component.create();
4744 QVERIFY(object != 0);
4749 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4751 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4753 QObject *object = component.create();
4754 QVERIFY(object != 0);
4756 QCOMPARE(object->property("test1").toInt(), 10);
4757 QCOMPARE(object->property("test2").toInt(), 11);
4759 object->setProperty("runTest", true);
4761 QCOMPARE(object->property("test1"), QVariant());
4762 QCOMPARE(object->property("test2"), QVariant());
4768 void tst_qdeclarativeecmascript::qtbug_9792()
4770 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4772 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4774 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4775 QVERIFY(object != 0);
4777 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4778 object->basicSignal();
4782 transientErrorsMsgCount = 0;
4783 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4785 object->basicSignal();
4787 qInstallMsgHandler(old);
4789 QCOMPARE(transientErrorsMsgCount, 0);
4794 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4795 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4797 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4799 QObject *o = component.create();
4802 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4803 QVERIFY(nested != 0);
4805 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4808 nested = qvariant_cast<QObject *>(o->property("object"));
4809 QVERIFY(nested == 0);
4811 // If the bug is present, the next line will crash
4815 // Test that we shut down without stupid warnings
4816 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4819 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4821 QObject *o = component.create();
4823 transientErrorsMsgCount = 0;
4824 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4828 qInstallMsgHandler(old);
4830 QCOMPARE(transientErrorsMsgCount, 0);
4835 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4837 QObject *o = component.create();
4839 transientErrorsMsgCount = 0;
4840 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4844 qInstallMsgHandler(old);
4846 QCOMPARE(transientErrorsMsgCount, 0);
4850 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4853 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4855 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4858 QVERIFY(o->objectProperty() != 0);
4860 o->setProperty("runTest", true);
4862 QVERIFY(o->objectProperty() == 0);
4868 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4870 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4873 QVERIFY(o->objectProperty() == 0);
4879 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4881 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4883 QString url = component.url().toString();
4884 QString warning = url + ":4: Unable to assign a function to a property.";
4885 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4887 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4890 QVERIFY(!o->property("a").isValid());
4895 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4897 QFETCH(QString, triggerProperty);
4899 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4900 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4902 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4904 QVERIFY(!o->property("a").isValid());
4906 o->setProperty("aNumber", QVariant(5));
4907 o->setProperty(triggerProperty.toUtf8().constData(), true);
4908 QCOMPARE(o->property("a"), QVariant(50));
4910 o->setProperty("aNumber", QVariant(10));
4911 QCOMPARE(o->property("a"), QVariant(100));
4916 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4918 QTest::addColumn<QString>("triggerProperty");
4920 QTest::newRow("assign to property") << "assignToProperty";
4921 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4923 QTest::newRow("assign to value type") << "assignToValueType";
4925 QTest::newRow("use 'this'") << "assignWithThis";
4926 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4929 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4931 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4932 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4934 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4936 QVERIFY(!o->property("a").isValid());
4938 o->setProperty("assignFuncWithoutReturn", true);
4939 QVERIFY(!o->property("a").isValid());
4941 QString url = component.url().toString();
4942 QString warning = url + ":67: Unable to assign QString to int";
4943 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4944 o->setProperty("assignWrongType", true);
4946 warning = url + ":71: Unable to assign QString to int";
4947 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4948 o->setProperty("assignWrongTypeToValueType", true);
4953 void tst_qdeclarativeecmascript::eval()
4955 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4957 QObject *o = component.create();
4960 QCOMPARE(o->property("test1").toBool(), true);
4961 QCOMPARE(o->property("test2").toBool(), true);
4962 QCOMPARE(o->property("test3").toBool(), true);
4963 QCOMPARE(o->property("test4").toBool(), true);
4964 QCOMPARE(o->property("test5").toBool(), true);
4969 void tst_qdeclarativeecmascript::function()
4971 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4973 QObject *o = component.create();
4976 QCOMPARE(o->property("test1").toBool(), true);
4977 QCOMPARE(o->property("test2").toBool(), true);
4978 QCOMPARE(o->property("test3").toBool(), true);
4983 // Test the "Qt.include" method
4984 void tst_qdeclarativeecmascript::include()
4986 // Non-library relative include
4988 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4989 QObject *o = component.create();
4992 QCOMPARE(o->property("test0").toInt(), 99);
4993 QCOMPARE(o->property("test1").toBool(), true);
4994 QCOMPARE(o->property("test2").toBool(), true);
4995 QCOMPARE(o->property("test2_1").toBool(), true);
4996 QCOMPARE(o->property("test3").toBool(), true);
4997 QCOMPARE(o->property("test3_1").toBool(), true);
5002 // Library relative include
5004 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
5005 QObject *o = component.create();
5008 QCOMPARE(o->property("test0").toInt(), 99);
5009 QCOMPARE(o->property("test1").toBool(), true);
5010 QCOMPARE(o->property("test2").toBool(), true);
5011 QCOMPARE(o->property("test2_1").toBool(), true);
5012 QCOMPARE(o->property("test3").toBool(), true);
5013 QCOMPARE(o->property("test3_1").toBool(), true);
5020 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
5021 QObject *o = component.create();
5024 QCOMPARE(o->property("test1").toBool(), true);
5025 QCOMPARE(o->property("test2").toBool(), true);
5026 QCOMPARE(o->property("test3").toBool(), true);
5027 QCOMPARE(o->property("test4").toBool(), true);
5028 QCOMPARE(o->property("test5").toBool(), true);
5029 QCOMPARE(o->property("test6").toBool(), true);
5034 // Including file with ".pragma library"
5036 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
5037 QObject *o = component.create();
5039 QCOMPARE(o->property("test1").toInt(), 100);
5046 TestHTTPServer server(8111);
5047 QVERIFY(server.isValid());
5048 server.serveDirectory(TESTDATA(""));
5050 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
5051 QObject *o = component.create();
5054 QTRY_VERIFY(o->property("done").toBool() == true);
5055 QTRY_VERIFY(o->property("done2").toBool() == true);
5057 QCOMPARE(o->property("test1").toBool(), true);
5058 QCOMPARE(o->property("test2").toBool(), true);
5059 QCOMPARE(o->property("test3").toBool(), true);
5060 QCOMPARE(o->property("test4").toBool(), true);
5061 QCOMPARE(o->property("test5").toBool(), true);
5063 QCOMPARE(o->property("test6").toBool(), true);
5064 QCOMPARE(o->property("test7").toBool(), true);
5065 QCOMPARE(o->property("test8").toBool(), true);
5066 QCOMPARE(o->property("test9").toBool(), true);
5067 QCOMPARE(o->property("test10").toBool(), true);
5074 TestHTTPServer server(8111);
5075 QVERIFY(server.isValid());
5076 server.serveDirectory(TESTDATA(""));
5078 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
5079 QObject *o = component.create();
5082 QTRY_VERIFY(o->property("done").toBool() == true);
5084 QCOMPARE(o->property("test1").toBool(), true);
5085 QCOMPARE(o->property("test2").toBool(), true);
5086 QCOMPARE(o->property("test3").toBool(), true);
5092 void tst_qdeclarativeecmascript::signalHandlers()
5094 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
5095 QObject *o = component.create();
5098 QVERIFY(o->property("count").toInt() == 0);
5099 QMetaObject::invokeMethod(o, "testSignalCall");
5100 QCOMPARE(o->property("count").toInt(), 1);
5102 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5103 QCOMPARE(o->property("count").toInt(), 1);
5104 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5106 QVERIFY(o->property("funcCount").toInt() == 0);
5107 QMetaObject::invokeMethod(o, "testSignalConnection");
5108 QCOMPARE(o->property("funcCount").toInt(), 1);
5110 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5111 QCOMPARE(o->property("funcCount").toInt(), 2);
5113 QMetaObject::invokeMethod(o, "testSignalDefined");
5114 QCOMPARE(o->property("definedResult").toBool(), true);
5116 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5117 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5122 void tst_qdeclarativeecmascript::qtbug_10696()
5124 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
5125 QObject *o = component.create();
5130 void tst_qdeclarativeecmascript::qtbug_11606()
5132 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
5133 QObject *o = component.create();
5135 QCOMPARE(o->property("test").toBool(), true);
5139 void tst_qdeclarativeecmascript::qtbug_11600()
5141 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
5142 QObject *o = component.create();
5144 QCOMPARE(o->property("test").toBool(), true);
5148 void tst_qdeclarativeecmascript::qtbug_21864()
5150 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21864.qml"));
5151 QObject *o = component.create();
5153 QCOMPARE(o->property("test").toBool(), true);
5157 // Reading and writing non-scriptable properties should fail
5158 void tst_qdeclarativeecmascript::nonscriptable()
5160 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
5161 QObject *o = component.create();
5163 QCOMPARE(o->property("readOk").toBool(), true);
5164 QCOMPARE(o->property("writeOk").toBool(), true);
5168 // deleteLater() should not be callable from QML
5169 void tst_qdeclarativeecmascript::deleteLater()
5171 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
5172 QObject *o = component.create();
5174 QCOMPARE(o->property("test").toBool(), true);
5178 void tst_qdeclarativeecmascript::in()
5180 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
5181 QObject *o = component.create();
5183 QCOMPARE(o->property("test1").toBool(), true);
5184 QCOMPARE(o->property("test2").toBool(), true);
5188 void tst_qdeclarativeecmascript::typeOf()
5190 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
5192 // These warnings should not happen once QTBUG-21864 is fixed
5193 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5194 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5196 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5197 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5199 QObject *o = component.create();
5202 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5203 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5204 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5205 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5206 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5207 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5208 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5209 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5210 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5211 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5216 void tst_qdeclarativeecmascript::sharedAttachedObject()
5218 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
5219 QObject *o = component.create();
5221 QCOMPARE(o->property("test1").toBool(), true);
5222 QCOMPARE(o->property("test2").toBool(), true);
5227 void tst_qdeclarativeecmascript::objectName()
5229 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
5230 QObject *o = component.create();
5233 QCOMPARE(o->property("test1").toString(), QString("hello"));
5234 QCOMPARE(o->property("test2").toString(), QString("ell"));
5236 o->setObjectName("world");
5238 QCOMPARE(o->property("test1").toString(), QString("world"));
5239 QCOMPARE(o->property("test2").toString(), QString("orl"));
5244 void tst_qdeclarativeecmascript::writeRemovesBinding()
5246 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
5247 QObject *o = component.create();
5250 QCOMPARE(o->property("test").toBool(), true);
5255 // Test bindings assigned to alias properties actually assign to the alias' target
5256 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5258 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
5259 QObject *o = component.create();
5262 QCOMPARE(o->property("test").toBool(), true);
5267 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5268 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5271 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
5272 QObject *o = component.create();
5275 QCOMPARE(o->property("test").toBool(), true);
5281 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
5282 QObject *o = component.create();
5285 QCOMPARE(o->property("test").toBool(), true);
5291 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
5292 QObject *o = component.create();
5295 QCOMPARE(o->property("test").toBool(), true);
5301 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5302 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5305 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
5306 QObject *o = component.create();
5309 QCOMPARE(o->property("test").toBool(), true);
5315 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
5316 QObject *o = component.create();
5319 QCOMPARE(o->property("test").toBool(), true);
5325 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
5326 QObject *o = component.create();
5329 QCOMPARE(o->property("test").toBool(), true);
5335 // Allow an alais to a composite element
5337 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5339 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
5341 QObject *object = component.create();
5342 QVERIFY(object != 0);
5347 void tst_qdeclarativeecmascript::qtbug_20344()
5349 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
5351 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5352 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5354 QObject *object = component.create();
5355 QVERIFY(object != 0);
5360 void tst_qdeclarativeecmascript::revisionErrors()
5363 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
5364 QString url = component.url().toString();
5366 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5367 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5368 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5370 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5371 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5372 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5373 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5374 QVERIFY(object != 0);
5378 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
5379 QString url = component.url().toString();
5381 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5382 // method2, prop2 from MyRevisionedClass not available
5383 // method4, prop4 from MyRevisionedSubclass not available
5384 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5385 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5386 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5387 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5388 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5390 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5391 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5392 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5393 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5394 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5395 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5396 QVERIFY(object != 0);
5400 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5401 QString url = component.url().toString();
5403 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5404 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5405 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5406 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5407 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5408 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5409 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5410 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5411 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5412 QVERIFY(object != 0);
5417 void tst_qdeclarativeecmascript::revision()
5420 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5421 QString url = component.url().toString();
5423 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5424 QVERIFY(object != 0);
5428 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5429 QString url = component.url().toString();
5431 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5432 QVERIFY(object != 0);
5436 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5437 QString url = component.url().toString();
5439 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5440 QVERIFY(object != 0);
5443 // Test that non-root classes can resolve revisioned methods
5445 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5447 QObject *object = component.create();
5448 QVERIFY(object != 0);
5449 QCOMPARE(object->property("test").toReal(), 11.);
5454 void tst_qdeclarativeecmascript::realToInt()
5456 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5457 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5458 QVERIFY(object != 0);
5460 QMetaObject::invokeMethod(object, "test1");
5461 QCOMPARE(object->value(), int(4));
5462 QMetaObject::invokeMethod(object, "test2");
5463 QCOMPARE(object->value(), int(8));
5465 void tst_qdeclarativeecmascript::dynamicString()
5467 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5468 QObject *object = component.create();
5469 QVERIFY(object != 0);
5470 QCOMPARE(object->property("stringProperty").toString(),
5471 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5474 void tst_qdeclarativeecmascript::automaticSemicolon()
5476 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5477 QObject *object = component.create();
5478 QVERIFY(object != 0);
5481 void tst_qdeclarativeecmascript::unaryExpression()
5483 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5484 QObject *object = component.create();
5485 QVERIFY(object != 0);
5488 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5489 void tst_qdeclarativeecmascript::doubleEvaluate()
5491 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5492 QObject *object = component.create();
5493 QVERIFY(object != 0);
5494 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5496 QCOMPARE(wc->count(), 1);
5498 wc->setProperty("x", 9);
5500 QCOMPARE(wc->count(), 2);
5505 static QStringList messages;
5506 static void captureMsgHandler(QtMsgType, const char *msg)
5508 messages.append(QLatin1String(msg));
5511 void tst_qdeclarativeecmascript::nonNotifyable()
5513 QV4Compiler::enableV4(false);
5514 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5515 QV4Compiler::enableV4(true);
5517 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5519 QObject *object = component.create();
5520 qInstallMsgHandler(old);
5522 QVERIFY(object != 0);
5524 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5525 component.url().toString() +
5526 QLatin1String(":5 depends on non-NOTIFYable properties:");
5527 QString expected2 = QLatin1String(" ") +
5528 QLatin1String(object->metaObject()->className()) +
5529 QLatin1String("::value");
5531 QCOMPARE(messages.length(), 2);
5532 QCOMPARE(messages.at(0), expected1);
5533 QCOMPARE(messages.at(1), expected2);
5538 void tst_qdeclarativeecmascript::forInLoop()
5540 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5541 QObject *object = component.create();
5542 QVERIFY(object != 0);
5544 QMetaObject::invokeMethod(object, "listProperty");
5546 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5547 QCOMPARE(r.size(), 3);
5548 QCOMPARE(r[0],QLatin1String("0=obj1"));
5549 QCOMPARE(r[1],QLatin1String("1=obj2"));
5550 QCOMPARE(r[2],QLatin1String("2=obj3"));
5552 //TODO: should test for in loop for other objects (such as QObjects) as well.
5557 // An object the binding depends on is deleted while the binding is still running
5558 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5560 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5561 QObject *object = component.create();
5562 QVERIFY(object != 0);
5566 void tst_qdeclarativeecmascript::qtbug_22679()
5569 object.setStringProperty(QLatin1String("Please work correctly"));
5570 engine.rootContext()->setContextProperty("contextProp", &object);
5572 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5573 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5574 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5576 QObject *o = component.create();
5578 QCOMPARE(warningsSpy.count(), 0);
5582 void tst_qdeclarativeecmascript::qtbug_22843_data()
5584 QTest::addColumn<bool>("library");
5586 QTest::newRow("without .pragma library") << false;
5587 QTest::newRow("with .pragma library") << true;
5590 void tst_qdeclarativeecmascript::qtbug_22843()
5592 QFETCH(bool, library);
5594 QString fileName("qtbug_22843");
5596 fileName += QLatin1String(".library");
5597 fileName += QLatin1String(".qml");
5599 QDeclarativeComponent component(&engine, TEST_FILE(fileName));
5600 QString url = component.url().toString();
5601 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5602 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5604 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5605 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5606 for (int x = 0; x < 3; ++x) {
5607 warningsSpy.clear();
5608 // For libraries, only the first import attempt should produce a
5609 // SyntaxError warning; subsequent component creation should not
5610 // attempt to reload the script.
5611 bool expectSyntaxError = !library || (x == 0);
5612 if (expectSyntaxError)
5613 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5614 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5615 QObject *object = component.create();
5616 QVERIFY(object != 0);
5617 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5623 void tst_qdeclarativeecmascript::switchStatement()
5626 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.1.qml"));
5627 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5628 QVERIFY(object != 0);
5630 // `object->value()' is the number of executed statements
5632 object->setStringProperty("A");
5633 QCOMPARE(object->value(), 5);
5635 object->setStringProperty("S");
5636 QCOMPARE(object->value(), 3);
5638 object->setStringProperty("D");
5639 QCOMPARE(object->value(), 3);
5641 object->setStringProperty("F");
5642 QCOMPARE(object->value(), 4);
5644 object->setStringProperty("something else");
5645 QCOMPARE(object->value(), 1);
5649 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.2.qml"));
5650 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5651 QVERIFY(object != 0);
5653 // `object->value()' is the number of executed statements
5655 object->setStringProperty("A");
5656 QCOMPARE(object->value(), 5);
5658 object->setStringProperty("S");
5659 QCOMPARE(object->value(), 3);
5661 object->setStringProperty("D");
5662 QCOMPARE(object->value(), 3);
5664 object->setStringProperty("F");
5665 QCOMPARE(object->value(), 3);
5667 object->setStringProperty("something else");
5668 QCOMPARE(object->value(), 4);
5672 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.3.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(), 3);
5690 object->setStringProperty("something else");
5691 QCOMPARE(object->value(), 6);
5695 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.4.qml"));
5697 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5698 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5700 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5701 QVERIFY(object != 0);
5703 // `object->value()' is the number of executed statements
5705 object->setStringProperty("A");
5706 QCOMPARE(object->value(), 5);
5708 object->setStringProperty("S");
5709 QCOMPARE(object->value(), 3);
5711 object->setStringProperty("D");
5712 QCOMPARE(object->value(), 3);
5714 object->setStringProperty("F");
5715 QCOMPARE(object->value(), 3);
5717 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5719 object->setStringProperty("something else");
5723 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.5.qml"));
5724 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5725 QVERIFY(object != 0);
5727 // `object->value()' is the number of executed statements
5729 object->setStringProperty("A");
5730 QCOMPARE(object->value(), 1);
5732 object->setStringProperty("S");
5733 QCOMPARE(object->value(), 1);
5735 object->setStringProperty("D");
5736 QCOMPARE(object->value(), 1);
5738 object->setStringProperty("F");
5739 QCOMPARE(object->value(), 1);
5741 object->setStringProperty("something else");
5742 QCOMPARE(object->value(), 1);
5746 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.6.qml"));
5747 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5748 QVERIFY(object != 0);
5750 // `object->value()' is the number of executed statements
5752 object->setStringProperty("A");
5753 QCOMPARE(object->value(), 123);
5755 object->setStringProperty("S");
5756 QCOMPARE(object->value(), 123);
5758 object->setStringProperty("D");
5759 QCOMPARE(object->value(), 321);
5761 object->setStringProperty("F");
5762 QCOMPARE(object->value(), 321);
5764 object->setStringProperty("something else");
5765 QCOMPARE(object->value(), 0);
5769 void tst_qdeclarativeecmascript::withStatement()
5772 QDeclarativeComponent component(&engine, TEST_FILE("withStatement.1.qml"));
5773 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5774 QVERIFY(object != 0);
5776 QCOMPARE(object->value(), 123);
5780 void tst_qdeclarativeecmascript::tryStatement()
5783 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.1.qml"));
5784 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5785 QVERIFY(object != 0);
5787 QCOMPARE(object->value(), 123);
5791 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.2.qml"));
5792 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5793 QVERIFY(object != 0);
5795 QCOMPARE(object->value(), 321);
5799 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.3.qml"));
5800 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5801 QVERIFY(object != 0);
5803 QCOMPARE(object->value(), 1);
5807 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.4.qml"));
5808 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5809 QVERIFY(object != 0);
5811 QCOMPARE(object->value(), 1);
5815 QTEST_MAIN(tst_qdeclarativeecmascript)
5817 #include "tst_qdeclarativeecmascript.moc"