1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include <private/qv8gccallback_p.h>
53 #include <private/qdeclarativevmemetaobject_p.h>
54 #include <private/qv4compiler_p.h>
55 #include "testtypes.h"
56 #include "testhttpserver.h"
57 #include "../../shared/util.h"
60 This test covers evaluation of ECMAScript expressions and bindings from within
61 QML. This does not include static QML language issues.
63 Static QML language issues are covered in qmllanguage
65 inline QUrl TEST_FILE(const QString &filename)
67 return QUrl::fromLocalFile(TESTDATA(filename));
70 inline QUrl TEST_FILE(const char *filename)
72 return TEST_FILE(QLatin1String(filename));
75 class tst_qdeclarativeecmascript : public QObject
79 tst_qdeclarativeecmascript() {}
83 void assignBasicTypes();
84 void idShortcutInvalidates();
85 void boolPropertiesEvaluateAsBool();
87 void signalAssignment();
89 void basicExpressions();
90 void basicExpressions_data();
91 void arrayExpressions();
92 void contextPropertiesTriggerReeval();
93 void objectPropertiesTriggerReeval();
94 void deferredProperties();
95 void deferredPropertiesErrors();
96 void extensionObjects();
97 void overrideExtensionProperties();
98 void attachedProperties();
100 void valueTypeFunctions();
101 void constantsOverrideBindings();
102 void outerBindingOverridesInnerBinding();
103 void aliasPropertyAndBinding();
104 void aliasPropertyReset();
105 void nonExistentAttachedObject();
108 void signalParameterTypes();
109 void objectsCompareAsEqual();
110 void dynamicCreation_data();
111 void dynamicCreation();
112 void dynamicDestruction();
113 void objectToString();
114 void objectHasOwnProperty();
115 void selfDeletingBinding();
116 void extendedObjectPropertyLookup();
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 moduleApi_data();
152 void importScripts_data();
153 void importScripts();
154 void scarceResources();
155 void scarceResources_data();
156 void scarceResources_other();
157 void propertyChangeSlots();
158 void propertyVar_data();
160 void propertyVarCpp();
161 void propertyVarOwnership();
162 void propertyVarImplicitOwnership();
163 void propertyVarReparent();
164 void propertyVarReparentNullContext();
165 void propertyVarCircular();
166 void propertyVarCircular2();
167 void propertyVarInheritance();
168 void propertyVarInheritance2();
169 void elementAssign();
170 void objectPassThroughSignals();
171 void objectConversion();
172 void booleanConversion();
173 void handleReferenceManagement();
175 void readonlyDeclaration();
176 void sequenceConversionRead();
177 void sequenceConversionWrite();
178 void sequenceConversionArray();
179 void sequenceConversionThreads();
180 void sequenceConversionBindings();
181 void sequenceConversionCopy();
182 void assignSequenceTypes();
188 void dynamicCreationCrash();
189 void dynamicCreationOwnership();
191 void nullObjectBinding();
192 void deletedEngine();
193 void libraryScriptAssert();
194 void variantsAssignedUndefined();
196 void qtcreatorbug_1289();
197 void noSpuriousWarningsAtShutdown();
198 void canAssignNullToQObject();
199 void functionAssignment_fromBinding();
200 void functionAssignment_fromJS();
201 void functionAssignment_fromJS_data();
202 void functionAssignmentfromJS_invalid();
209 void nonscriptable();
213 void sharedAttachedObject();
215 void writeRemovesBinding();
216 void aliasBindingsAssignCorrectly();
217 void aliasBindingsOverrideTarget();
218 void aliasWritesOverrideBindings();
219 void aliasToCompositeElement();
221 void dynamicString();
223 void signalHandlers();
224 void doubleEvaluate();
226 void nonNotifyable();
227 void deleteWhileBindingRunning();
228 void callQtInvokables();
229 void invokableObjectArg();
230 void invokableObjectRet();
233 void qtbug_22843_data();
235 void revisionErrors();
238 void automaticSemicolon();
239 void unaryExpression();
240 void switchStatement();
241 void withStatement();
245 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
246 QDeclarativeEngine engine;
249 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
251 void tst_qdeclarativeecmascript::assignBasicTypes()
254 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
255 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
256 QVERIFY(object != 0);
257 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
258 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
259 QCOMPARE(object->stringProperty(), QString("Hello World!"));
260 QCOMPARE(object->uintProperty(), uint(10));
261 QCOMPARE(object->intProperty(), -19);
262 QCOMPARE((float)object->realProperty(), float(23.2));
263 QCOMPARE((float)object->doubleProperty(), float(-19.75));
264 QCOMPARE((float)object->floatProperty(), float(8.5));
265 QCOMPARE(object->colorProperty(), QColor("red"));
266 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
267 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
268 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
269 QCOMPARE(object->pointProperty(), QPoint(99,13));
270 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
271 QCOMPARE(object->sizeProperty(), QSize(99, 13));
272 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
273 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
274 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
275 QCOMPARE(object->boolProperty(), true);
276 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
277 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
278 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
282 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
283 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
284 QVERIFY(object != 0);
285 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
286 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
287 QCOMPARE(object->stringProperty(), QString("Hello World!"));
288 QCOMPARE(object->uintProperty(), uint(10));
289 QCOMPARE(object->intProperty(), -19);
290 QCOMPARE((float)object->realProperty(), float(23.2));
291 QCOMPARE((float)object->doubleProperty(), float(-19.75));
292 QCOMPARE((float)object->floatProperty(), float(8.5));
293 QCOMPARE(object->colorProperty(), QColor("red"));
294 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
295 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
296 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
297 QCOMPARE(object->pointProperty(), QPoint(99,13));
298 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
299 QCOMPARE(object->sizeProperty(), QSize(99, 13));
300 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
301 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
302 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
303 QCOMPARE(object->boolProperty(), true);
304 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
305 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
306 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
311 void tst_qdeclarativeecmascript::idShortcutInvalidates()
314 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
315 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
316 QVERIFY(object != 0);
317 QVERIFY(object->objectProperty() != 0);
318 delete object->objectProperty();
319 QVERIFY(object->objectProperty() == 0);
324 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
325 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
326 QVERIFY(object != 0);
327 QVERIFY(object->objectProperty() != 0);
328 delete object->objectProperty();
329 QVERIFY(object->objectProperty() == 0);
334 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
337 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
338 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
339 QVERIFY(object != 0);
340 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
344 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
345 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
346 QVERIFY(object != 0);
347 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
352 void tst_qdeclarativeecmascript::signalAssignment()
355 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
356 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
357 QVERIFY(object != 0);
358 QCOMPARE(object->string(), QString());
359 emit object->basicSignal();
360 QCOMPARE(object->string(), QString("pass"));
365 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
366 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
367 QVERIFY(object != 0);
368 QCOMPARE(object->string(), QString());
369 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
370 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
375 void tst_qdeclarativeecmascript::methods()
378 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
379 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
380 QVERIFY(object != 0);
381 QCOMPARE(object->methodCalled(), false);
382 QCOMPARE(object->methodIntCalled(), false);
383 emit object->basicSignal();
384 QCOMPARE(object->methodCalled(), true);
385 QCOMPARE(object->methodIntCalled(), false);
390 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
391 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
392 QVERIFY(object != 0);
393 QCOMPARE(object->methodCalled(), false);
394 QCOMPARE(object->methodIntCalled(), false);
395 emit object->basicSignal();
396 QCOMPARE(object->methodCalled(), false);
397 QCOMPARE(object->methodIntCalled(), true);
402 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
403 QObject *object = component.create();
404 QVERIFY(object != 0);
405 QCOMPARE(object->property("test").toInt(), 19);
410 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
411 QObject *object = component.create();
412 QVERIFY(object != 0);
413 QCOMPARE(object->property("test").toInt(), 19);
414 QCOMPARE(object->property("test2").toInt(), 17);
415 QCOMPARE(object->property("test3").toInt(), 16);
420 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
421 QObject *object = component.create();
422 QVERIFY(object != 0);
423 QCOMPARE(object->property("test").toInt(), 9);
428 void tst_qdeclarativeecmascript::bindingLoop()
430 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
431 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
432 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
433 QObject *object = component.create();
434 QVERIFY(object != 0);
438 void tst_qdeclarativeecmascript::basicExpressions_data()
440 QTest::addColumn<QString>("expression");
441 QTest::addColumn<QVariant>("result");
442 QTest::addColumn<bool>("nest");
444 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
445 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
446 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
447 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
448 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
449 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
450 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
451 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
452 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
453 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
454 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
455 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
456 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
457 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
458 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
459 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
460 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
461 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
462 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
465 void tst_qdeclarativeecmascript::basicExpressions()
467 QFETCH(QString, expression);
468 QFETCH(QVariant, result);
474 MyDefaultObject1 default1;
475 MyDefaultObject3 default3;
476 object1.setStringProperty("Object1");
477 object2.setStringProperty("Object2");
478 object3.setStringProperty("Object3");
480 QDeclarativeContext context(engine.rootContext());
481 QDeclarativeContext nestedContext(&context);
483 context.setContextObject(&default1);
484 context.setContextProperty("a", QVariant(1944));
485 context.setContextProperty("b", QVariant("Milk"));
486 context.setContextProperty("object", &object1);
487 context.setContextProperty("objectOverride", &object2);
488 nestedContext.setContextObject(&default3);
489 nestedContext.setContextProperty("b", QVariant("Cow"));
490 nestedContext.setContextProperty("objectOverride", &object3);
491 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
493 MyExpression expr(nest?&nestedContext:&context, expression);
494 QCOMPARE(expr.evaluate(), result);
497 void tst_qdeclarativeecmascript::arrayExpressions()
503 QDeclarativeContext context(engine.rootContext());
504 context.setContextProperty("a", &obj1);
505 context.setContextProperty("b", &obj2);
506 context.setContextProperty("c", &obj3);
508 MyExpression expr(&context, "[a, b, c, 10]");
509 QVariant result = expr.evaluate();
510 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
511 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
512 QCOMPARE(list.count(), 4);
513 QCOMPARE(list.at(0), &obj1);
514 QCOMPARE(list.at(1), &obj2);
515 QCOMPARE(list.at(2), &obj3);
516 QCOMPARE(list.at(3), (QObject *)0);
519 // Tests that modifying a context property will reevaluate expressions
520 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
522 QDeclarativeContext context(engine.rootContext());
525 MyQmlObject *object3 = new MyQmlObject;
527 object1.setStringProperty("Hello");
528 object2.setStringProperty("World");
530 context.setContextProperty("testProp", QVariant(1));
531 context.setContextProperty("testObj", &object1);
532 context.setContextProperty("testObj2", object3);
535 MyExpression expr(&context, "testProp + 1");
536 QCOMPARE(expr.changed, false);
537 QCOMPARE(expr.evaluate(), QVariant(2));
539 context.setContextProperty("testProp", QVariant(2));
540 QCOMPARE(expr.changed, true);
541 QCOMPARE(expr.evaluate(), QVariant(3));
545 MyExpression expr(&context, "testProp + testProp + testProp");
546 QCOMPARE(expr.changed, false);
547 QCOMPARE(expr.evaluate(), QVariant(6));
549 context.setContextProperty("testProp", QVariant(4));
550 QCOMPARE(expr.changed, true);
551 QCOMPARE(expr.evaluate(), QVariant(12));
555 MyExpression expr(&context, "testObj.stringProperty");
556 QCOMPARE(expr.changed, false);
557 QCOMPARE(expr.evaluate(), QVariant("Hello"));
559 context.setContextProperty("testObj", &object2);
560 QCOMPARE(expr.changed, true);
561 QCOMPARE(expr.evaluate(), QVariant("World"));
565 MyExpression expr(&context, "testObj.stringProperty /**/");
566 QCOMPARE(expr.changed, false);
567 QCOMPARE(expr.evaluate(), QVariant("World"));
569 context.setContextProperty("testObj", &object1);
570 QCOMPARE(expr.changed, true);
571 QCOMPARE(expr.evaluate(), QVariant("Hello"));
575 MyExpression expr(&context, "testObj2");
576 QCOMPARE(expr.changed, false);
577 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
583 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
585 QDeclarativeContext context(engine.rootContext());
589 context.setContextProperty("testObj", &object1);
591 object1.setStringProperty(QLatin1String("Hello"));
592 object2.setStringProperty(QLatin1String("Dog"));
593 object3.setStringProperty(QLatin1String("Cat"));
596 MyExpression expr(&context, "testObj.stringProperty");
597 QCOMPARE(expr.changed, false);
598 QCOMPARE(expr.evaluate(), QVariant("Hello"));
600 object1.setStringProperty(QLatin1String("World"));
601 QCOMPARE(expr.changed, true);
602 QCOMPARE(expr.evaluate(), QVariant("World"));
606 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
607 QCOMPARE(expr.changed, false);
608 QCOMPARE(expr.evaluate(), QVariant());
610 object1.setObjectProperty(&object2);
611 QCOMPARE(expr.changed, true);
612 expr.changed = false;
613 QCOMPARE(expr.evaluate(), QVariant("Dog"));
615 object1.setObjectProperty(&object3);
616 QCOMPARE(expr.changed, true);
617 expr.changed = false;
618 QCOMPARE(expr.evaluate(), QVariant("Cat"));
620 object1.setObjectProperty(0);
621 QCOMPARE(expr.changed, true);
622 expr.changed = false;
623 QCOMPARE(expr.evaluate(), QVariant());
625 object1.setObjectProperty(&object3);
626 QCOMPARE(expr.changed, true);
627 expr.changed = false;
628 QCOMPARE(expr.evaluate(), QVariant("Cat"));
630 object3.setStringProperty("Donkey");
631 QCOMPARE(expr.changed, true);
632 expr.changed = false;
633 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
637 void tst_qdeclarativeecmascript::deferredProperties()
639 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
640 MyDeferredObject *object =
641 qobject_cast<MyDeferredObject *>(component.create());
642 QVERIFY(object != 0);
643 QCOMPARE(object->value(), 0);
644 QVERIFY(object->objectProperty() == 0);
645 QVERIFY(object->objectProperty2() != 0);
646 qmlExecuteDeferred(object);
647 QCOMPARE(object->value(), 10);
648 QVERIFY(object->objectProperty() != 0);
649 MyQmlObject *qmlObject =
650 qobject_cast<MyQmlObject *>(object->objectProperty());
651 QVERIFY(qmlObject != 0);
652 QCOMPARE(qmlObject->value(), 10);
653 object->setValue(19);
654 QCOMPARE(qmlObject->value(), 19);
659 // Check errors on deferred properties are correctly emitted
660 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
662 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
663 MyDeferredObject *object =
664 qobject_cast<MyDeferredObject *>(component.create());
665 QVERIFY(object != 0);
666 QCOMPARE(object->value(), 0);
667 QVERIFY(object->objectProperty() == 0);
668 QVERIFY(object->objectProperty2() == 0);
670 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
671 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
673 qmlExecuteDeferred(object);
678 void tst_qdeclarativeecmascript::extensionObjects()
680 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
681 MyExtendedObject *object =
682 qobject_cast<MyExtendedObject *>(component.create());
683 QVERIFY(object != 0);
684 QCOMPARE(object->baseProperty(), 13);
685 QCOMPARE(object->coreProperty(), 9);
686 object->setProperty("extendedProperty", QVariant(11));
687 object->setProperty("baseExtendedProperty", QVariant(92));
688 QCOMPARE(object->coreProperty(), 11);
689 QCOMPARE(object->baseProperty(), 92);
691 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
693 QCOMPARE(nested->baseProperty(), 13);
694 QCOMPARE(nested->coreProperty(), 9);
695 nested->setProperty("extendedProperty", QVariant(11));
696 nested->setProperty("baseExtendedProperty", QVariant(92));
697 QCOMPARE(nested->coreProperty(), 11);
698 QCOMPARE(nested->baseProperty(), 92);
703 void tst_qdeclarativeecmascript::overrideExtensionProperties()
705 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
706 OverrideDefaultPropertyObject *object =
707 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
708 QVERIFY(object != 0);
709 QVERIFY(object->secondProperty() != 0);
710 QVERIFY(object->firstProperty() == 0);
715 void tst_qdeclarativeecmascript::attachedProperties()
718 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
719 QObject *object = component.create();
720 QVERIFY(object != 0);
721 QCOMPARE(object->property("a").toInt(), 19);
722 QCOMPARE(object->property("b").toInt(), 19);
723 QCOMPARE(object->property("c").toInt(), 19);
724 QCOMPARE(object->property("d").toInt(), 19);
729 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
730 QObject *object = component.create();
731 QVERIFY(object != 0);
732 QCOMPARE(object->property("a").toInt(), 26);
733 QCOMPARE(object->property("b").toInt(), 26);
734 QCOMPARE(object->property("c").toInt(), 26);
735 QCOMPARE(object->property("d").toInt(), 26);
741 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
742 QObject *object = component.create();
743 QVERIFY(object != 0);
745 QMetaObject::invokeMethod(object, "writeValue2");
747 MyQmlAttachedObject *attached =
748 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
749 QVERIFY(attached != 0);
751 QCOMPARE(attached->value2(), 9);
756 void tst_qdeclarativeecmascript::enums()
760 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
761 QObject *object = component.create();
762 QVERIFY(object != 0);
764 QCOMPARE(object->property("a").toInt(), 0);
765 QCOMPARE(object->property("b").toInt(), 1);
766 QCOMPARE(object->property("c").toInt(), 2);
767 QCOMPARE(object->property("d").toInt(), 3);
768 QCOMPARE(object->property("e").toInt(), 0);
769 QCOMPARE(object->property("f").toInt(), 1);
770 QCOMPARE(object->property("g").toInt(), 2);
771 QCOMPARE(object->property("h").toInt(), 3);
772 QCOMPARE(object->property("i").toInt(), 19);
773 QCOMPARE(object->property("j").toInt(), 19);
777 // Non-existent enums
779 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
781 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
782 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
783 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
784 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
786 QObject *object = component.create();
787 QVERIFY(object != 0);
788 QCOMPARE(object->property("a").toInt(), 0);
789 QCOMPARE(object->property("b").toInt(), 0);
795 void tst_qdeclarativeecmascript::valueTypeFunctions()
797 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
798 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
800 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
801 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
807 Tests that writing a constant to a property with a binding on it disables the
810 void tst_qdeclarativeecmascript::constantsOverrideBindings()
814 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
815 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
816 QVERIFY(object != 0);
818 QCOMPARE(object->property("c2").toInt(), 0);
819 object->setProperty("c1", QVariant(9));
820 QCOMPARE(object->property("c2").toInt(), 9);
822 emit object->basicSignal();
824 QCOMPARE(object->property("c2").toInt(), 13);
825 object->setProperty("c1", QVariant(8));
826 QCOMPARE(object->property("c2").toInt(), 13);
831 // During construction
833 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
834 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
835 QVERIFY(object != 0);
837 QCOMPARE(object->property("c1").toInt(), 0);
838 QCOMPARE(object->property("c2").toInt(), 10);
839 object->setProperty("c1", QVariant(9));
840 QCOMPARE(object->property("c1").toInt(), 9);
841 QCOMPARE(object->property("c2").toInt(), 10);
849 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
850 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
851 QVERIFY(object != 0);
853 QCOMPARE(object->property("c2").toInt(), 0);
854 object->setProperty("c1", QVariant(9));
855 QCOMPARE(object->property("c2").toInt(), 9);
857 object->setProperty("c2", QVariant(13));
858 QCOMPARE(object->property("c2").toInt(), 13);
859 object->setProperty("c1", QVariant(7));
860 QCOMPARE(object->property("c1").toInt(), 7);
861 QCOMPARE(object->property("c2").toInt(), 13);
869 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
870 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
871 QVERIFY(object != 0);
873 QCOMPARE(object->property("c1").toInt(), 0);
874 QCOMPARE(object->property("c3").toInt(), 10);
875 object->setProperty("c1", QVariant(9));
876 QCOMPARE(object->property("c1").toInt(), 9);
877 QCOMPARE(object->property("c3").toInt(), 10);
884 Tests that assigning a binding to a property that already has a binding causes
885 the original binding to be disabled.
887 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
889 QDeclarativeComponent component(&engine,
890 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
891 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
892 QVERIFY(object != 0);
894 QCOMPARE(object->property("c1").toInt(), 0);
895 QCOMPARE(object->property("c2").toInt(), 0);
896 QCOMPARE(object->property("c3").toInt(), 0);
898 object->setProperty("c1", QVariant(9));
899 QCOMPARE(object->property("c1").toInt(), 9);
900 QCOMPARE(object->property("c2").toInt(), 0);
901 QCOMPARE(object->property("c3").toInt(), 0);
903 object->setProperty("c3", QVariant(8));
904 QCOMPARE(object->property("c1").toInt(), 9);
905 QCOMPARE(object->property("c2").toInt(), 8);
906 QCOMPARE(object->property("c3").toInt(), 8);
912 Access a non-existent attached object.
914 Tests for a regression where this used to crash.
916 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
918 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
920 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
921 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
923 QObject *object = component.create();
924 QVERIFY(object != 0);
929 void tst_qdeclarativeecmascript::scope()
932 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
933 QObject *object = component.create();
934 QVERIFY(object != 0);
936 QCOMPARE(object->property("test1").toInt(), 1);
937 QCOMPARE(object->property("test2").toInt(), 2);
938 QCOMPARE(object->property("test3").toString(), QString("1Test"));
939 QCOMPARE(object->property("test4").toString(), QString("2Test"));
940 QCOMPARE(object->property("test5").toInt(), 1);
941 QCOMPARE(object->property("test6").toInt(), 1);
942 QCOMPARE(object->property("test7").toInt(), 2);
943 QCOMPARE(object->property("test8").toInt(), 2);
944 QCOMPARE(object->property("test9").toInt(), 1);
945 QCOMPARE(object->property("test10").toInt(), 3);
951 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
952 QObject *object = component.create();
953 QVERIFY(object != 0);
955 QCOMPARE(object->property("test1").toInt(), 19);
956 QCOMPARE(object->property("test2").toInt(), 19);
957 QCOMPARE(object->property("test3").toInt(), 14);
958 QCOMPARE(object->property("test4").toInt(), 14);
959 QCOMPARE(object->property("test5").toInt(), 24);
960 QCOMPARE(object->property("test6").toInt(), 24);
966 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
967 QObject *object = component.create();
968 QVERIFY(object != 0);
970 QCOMPARE(object->property("test1").toBool(), true);
971 QCOMPARE(object->property("test2").toBool(), true);
972 QCOMPARE(object->property("test3").toBool(), true);
977 // Signal argument scope
979 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
980 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
981 QVERIFY(object != 0);
983 QCOMPARE(object->property("test").toInt(), 0);
984 QCOMPARE(object->property("test2").toString(), QString());
986 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
988 QCOMPARE(object->property("test").toInt(), 13);
989 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
995 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
996 QObject *object = component.create();
997 QVERIFY(object != 0);
999 QCOMPARE(object->property("test1").toBool(), true);
1000 QCOMPARE(object->property("test2").toBool(), true);
1006 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
1007 QObject *object = component.create();
1008 QVERIFY(object != 0);
1010 QCOMPARE(object->property("test").toBool(), true);
1016 // In 4.7, non-library javascript files that had no imports shared the imports of their
1017 // importing context
1018 void tst_qdeclarativeecmascript::importScope()
1020 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1021 QObject *o = component.create();
1024 QCOMPARE(o->property("test").toInt(), 240);
1030 Tests that "any" type passes through a synthesized signal parameter. This
1031 is essentially a test of QDeclarativeMetaType::copy()
1033 void tst_qdeclarativeecmascript::signalParameterTypes()
1035 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1036 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1037 QVERIFY(object != 0);
1039 emit object->basicSignal();
1041 QCOMPARE(object->property("intProperty").toInt(), 10);
1042 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1043 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1044 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1045 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1046 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1052 Test that two JS objects for the same QObject compare as equal.
1054 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1056 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1057 QObject *object = component.create();
1058 QVERIFY(object != 0);
1060 QCOMPARE(object->property("test1").toBool(), true);
1061 QCOMPARE(object->property("test2").toBool(), true);
1062 QCOMPARE(object->property("test3").toBool(), true);
1063 QCOMPARE(object->property("test4").toBool(), true);
1064 QCOMPARE(object->property("test5").toBool(), true);
1070 Confirm bindings and alias properties can coexist.
1072 Tests for a regression where the binding would not reevaluate.
1074 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1076 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1077 QObject *object = component.create();
1078 QVERIFY(object != 0);
1080 QCOMPARE(object->property("c2").toInt(), 3);
1081 QCOMPARE(object->property("c3").toInt(), 3);
1083 object->setProperty("c2", QVariant(19));
1085 QCOMPARE(object->property("c2").toInt(), 19);
1086 QCOMPARE(object->property("c3").toInt(), 19);
1092 Ensure that we can write undefined value to an alias property,
1093 and that the aliased property is reset correctly if possible.
1095 void tst_qdeclarativeecmascript::aliasPropertyReset()
1097 QObject *object = 0;
1099 // test that a manual write (of undefined) to a resettable aliased property succeeds
1100 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1101 object = c1.create();
1102 QVERIFY(object != 0);
1103 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1104 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1105 QMetaObject::invokeMethod(object, "resetAliased");
1106 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1107 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1110 // test that a manual write (of undefined) to a resettable alias property succeeds
1111 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1112 object = c2.create();
1113 QVERIFY(object != 0);
1114 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1115 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1116 QMetaObject::invokeMethod(object, "resetAlias");
1117 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1118 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1121 // test that an alias to a bound property works correctly
1122 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1123 object = c3.create();
1124 QVERIFY(object != 0);
1125 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1126 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1127 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1128 QMetaObject::invokeMethod(object, "resetAlias");
1129 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1130 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1131 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1134 // test that a manual write (of undefined) to a resettable alias property
1135 // whose aliased property's object has been deleted, does not crash.
1136 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1137 object = c4.create();
1138 QVERIFY(object != 0);
1139 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1140 QObject *loader = object->findChild<QObject*>("loader");
1141 QVERIFY(loader != 0);
1143 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1144 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1145 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1146 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1147 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1150 // test that binding an alias property to an undefined value works correctly
1151 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1152 object = c5.create();
1153 QVERIFY(object != 0);
1154 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1157 // test that a manual write (of undefined) to a non-resettable property fails properly
1158 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1159 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1160 QDeclarativeComponent e1(&engine, url);
1161 object = e1.create();
1162 QVERIFY(object != 0);
1163 QCOMPARE(object->property("intAlias").value<int>(), 12);
1164 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1165 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1166 QMetaObject::invokeMethod(object, "resetAlias");
1167 QCOMPARE(object->property("intAlias").value<int>(), 12);
1168 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1172 void tst_qdeclarativeecmascript::dynamicCreation_data()
1174 QTest::addColumn<QString>("method");
1175 QTest::addColumn<QString>("createdName");
1177 QTest::newRow("One") << "createOne" << "objectOne";
1178 QTest::newRow("Two") << "createTwo" << "objectTwo";
1179 QTest::newRow("Three") << "createThree" << "objectThree";
1183 Test using createQmlObject to dynamically generate an item
1184 Also using createComponent is tested.
1186 void tst_qdeclarativeecmascript::dynamicCreation()
1188 QFETCH(QString, method);
1189 QFETCH(QString, createdName);
1191 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1192 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1193 QVERIFY(object != 0);
1195 QMetaObject::invokeMethod(object, method.toUtf8());
1196 QObject *created = object->objectProperty();
1198 QCOMPARE(created->objectName(), createdName);
1204 Tests the destroy function
1206 void tst_qdeclarativeecmascript::dynamicDestruction()
1209 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1210 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1211 QVERIFY(object != 0);
1212 QDeclarativeGuard<QObject> createdQmlObject = 0;
1214 QMetaObject::invokeMethod(object, "create");
1215 createdQmlObject = object->objectProperty();
1216 QVERIFY(createdQmlObject);
1217 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1219 QMetaObject::invokeMethod(object, "killOther");
1220 QVERIFY(createdQmlObject);
1221 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1222 QVERIFY(createdQmlObject);
1223 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1224 if (createdQmlObject) {
1226 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1229 QVERIFY(!createdQmlObject);
1231 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1232 QMetaObject::invokeMethod(object, "killMe");
1235 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1240 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1241 QObject *o = component.create();
1244 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1246 QMetaObject::invokeMethod(o, "create");
1248 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1250 QMetaObject::invokeMethod(o, "destroy");
1252 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1254 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1261 tests that id.toString() works
1263 void tst_qdeclarativeecmascript::objectToString()
1265 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1266 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1267 QVERIFY(object != 0);
1268 QMetaObject::invokeMethod(object, "testToString");
1269 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1270 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1276 tests that id.hasOwnProperty() works
1278 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1280 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1281 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1282 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1283 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1285 QDeclarativeComponent component(&engine, url);
1286 QObject *object = component.create();
1287 QVERIFY(object != 0);
1289 // test QObjects in QML
1290 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1291 QVERIFY(object->property("result").value<bool>() == true);
1292 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1293 QVERIFY(object->property("result").value<bool>() == false);
1295 // now test other types in QML
1296 QObject *child = object->findChild<QObject*>("typeObj");
1297 QVERIFY(child != 0);
1298 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1299 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1300 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1301 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1302 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1303 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1304 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1305 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1306 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1307 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1308 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1309 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1311 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1312 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1313 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1314 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1315 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1316 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1317 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1318 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1319 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1325 Tests bindings that indirectly cause their own deletion work.
1327 This test is best run under valgrind to ensure no invalid memory access occur.
1329 void tst_qdeclarativeecmascript::selfDeletingBinding()
1332 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1333 QObject *object = component.create();
1334 QVERIFY(object != 0);
1335 object->setProperty("triggerDelete", true);
1340 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1341 QObject *object = component.create();
1342 QVERIFY(object != 0);
1343 object->setProperty("triggerDelete", true);
1349 Test that extended object properties can be accessed.
1351 This test a regression where this used to crash. The issue was specificially
1352 for extended objects that did not include a synthesized meta object (so non-root
1353 and no synthesiszed properties).
1355 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1357 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1358 QObject *object = component.create();
1359 QVERIFY(object != 0);
1364 Test file/lineNumbers for binding/Script errors.
1366 void tst_qdeclarativeecmascript::scriptErrors()
1368 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1369 QString url = component.url().toString();
1371 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1372 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1373 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1374 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1375 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1376 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1377 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1378 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1380 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1381 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1382 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1383 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1384 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1385 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1386 QVERIFY(object != 0);
1388 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1389 emit object->basicSignal();
1391 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1392 emit object->anotherBasicSignal();
1394 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1395 emit object->thirdBasicSignal();
1401 Test file/lineNumbers for inline functions.
1403 void tst_qdeclarativeecmascript::functionErrors()
1405 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1406 QString url = component.url().toString();
1408 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1410 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1412 QObject *object = component.create();
1413 QVERIFY(object != 0);
1416 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1417 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
1418 url = componentTwo.url().toString();
1419 object = componentTwo.create();
1420 QVERIFY(object != 0);
1422 QString srpname = object->property("srp_name").toString();
1424 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1425 + QLatin1String(" is not a function");
1426 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1427 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1432 Test various errors that can occur when assigning a property from script
1434 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1436 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1438 QString url = component.url().toString();
1440 QObject *object = component.create();
1441 QVERIFY(object != 0);
1443 QCOMPARE(object->property("test1").toBool(), true);
1444 QCOMPARE(object->property("test2").toBool(), true);
1450 Test bindings still work when the reeval is triggered from within
1453 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1455 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1456 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1457 QVERIFY(object != 0);
1459 QCOMPARE(object->property("base").toReal(), 50.);
1460 QCOMPARE(object->property("test1").toReal(), 50.);
1461 QCOMPARE(object->property("test2").toReal(), 50.);
1463 object->basicSignal();
1465 QCOMPARE(object->property("base").toReal(), 200.);
1466 QCOMPARE(object->property("test1").toReal(), 200.);
1467 QCOMPARE(object->property("test2").toReal(), 200.);
1469 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1471 QCOMPARE(object->property("base").toReal(), 400.);
1472 QCOMPARE(object->property("test1").toReal(), 400.);
1473 QCOMPARE(object->property("test2").toReal(), 400.);
1479 Test that list properties can be iterated from ECMAScript
1481 void tst_qdeclarativeecmascript::listProperties()
1483 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1484 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1485 QVERIFY(object != 0);
1487 QCOMPARE(object->property("test1").toInt(), 21);
1488 QCOMPARE(object->property("test2").toInt(), 2);
1489 QCOMPARE(object->property("test3").toBool(), true);
1490 QCOMPARE(object->property("test4").toBool(), true);
1495 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1497 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1498 QString url = component.url().toString();
1500 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1502 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1503 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1504 QVERIFY(object != 0);
1506 QCOMPARE(object->property("test").toBool(), false);
1508 MyQmlObject object2;
1509 MyQmlObject object3;
1510 object2.setObjectProperty(&object3);
1511 object->setObjectProperty(&object2);
1513 QCOMPARE(object->property("test").toBool(), true);
1518 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1520 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1521 QString url = component.url().toString();
1523 QString warning = component.url().toString() + ":6: Error: JS exception";
1525 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1526 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1527 QVERIFY(object != 0);
1531 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1533 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1534 QString url = component.url().toString();
1536 QString warning = component.url().toString() + ":5: Error: JS exception";
1538 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1539 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1540 QVERIFY(object != 0);
1544 static int transientErrorsMsgCount = 0;
1545 static void transientErrorsMsgHandler(QtMsgType, const char *)
1547 ++transientErrorsMsgCount;
1550 // Check that transient binding errors are not displayed
1551 void tst_qdeclarativeecmascript::transientErrors()
1554 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1556 transientErrorsMsgCount = 0;
1557 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1559 QObject *object = component.create();
1560 QVERIFY(object != 0);
1562 qInstallMsgHandler(old);
1564 QCOMPARE(transientErrorsMsgCount, 0);
1569 // One binding erroring multiple times, but then resolving
1571 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.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);
1587 // Check that errors during shutdown are minimized
1588 void tst_qdeclarativeecmascript::shutdownErrors()
1590 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1591 QObject *object = component.create();
1592 QVERIFY(object != 0);
1594 transientErrorsMsgCount = 0;
1595 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1599 qInstallMsgHandler(old);
1600 QCOMPARE(transientErrorsMsgCount, 0);
1603 void tst_qdeclarativeecmascript::compositePropertyType()
1605 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1607 QTest::ignoreMessage(QtDebugMsg, "hello world");
1608 QObject *object = qobject_cast<QObject *>(component.create());
1613 void tst_qdeclarativeecmascript::jsObject()
1615 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1616 QObject *object = component.create();
1617 QVERIFY(object != 0);
1619 QCOMPARE(object->property("test").toInt(), 92);
1624 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1627 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1628 QObject *object = component.create();
1629 QVERIFY(object != 0);
1631 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1633 object->setProperty("setUndefined", true);
1635 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1637 object->setProperty("setUndefined", false);
1639 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1644 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1645 QObject *object = component.create();
1646 QVERIFY(object != 0);
1648 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1650 QMetaObject::invokeMethod(object, "doReset");
1652 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1658 // Aliases to variant properties should work
1659 void tst_qdeclarativeecmascript::qtbug_22464()
1661 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1662 QObject *object = component.create();
1663 QVERIFY(object != 0);
1665 QCOMPARE(object->property("test").toBool(), true);
1670 void tst_qdeclarativeecmascript::qtbug_21580()
1672 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
1674 QObject *object = component.create();
1675 QVERIFY(object != 0);
1677 QCOMPARE(object->property("test").toBool(), true);
1683 void tst_qdeclarativeecmascript::bug1()
1685 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1686 QObject *object = component.create();
1687 QVERIFY(object != 0);
1689 QCOMPARE(object->property("test").toInt(), 14);
1691 object->setProperty("a", 11);
1693 QCOMPARE(object->property("test").toInt(), 3);
1695 object->setProperty("b", true);
1697 QCOMPARE(object->property("test").toInt(), 9);
1702 void tst_qdeclarativeecmascript::bug2()
1704 QDeclarativeComponent component(&engine);
1705 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1707 QObject *object = component.create();
1708 QVERIFY(object != 0);
1713 // Don't crash in createObject when the component has errors.
1714 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1716 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1717 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1718 QVERIFY(object != 0);
1720 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1721 QMetaObject::invokeMethod(object, "dontCrash");
1722 QObject *created = object->objectProperty();
1723 QVERIFY(created == 0);
1728 // ownership transferred to JS, ensure that GC runs the dtor
1729 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1732 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1734 // allow the engine to go out of scope too.
1736 QDeclarativeEngine dcoEngine;
1737 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1738 QObject *object = component.create();
1739 QVERIFY(object != 0);
1740 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1741 QVERIFY(mdcdo != 0);
1742 mdcdo->setDtorCount(&dtorCount);
1744 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1745 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1747 // we do this once manually, but it should be done automatically
1748 // when the engine goes out of scope (since it should gc in dtor)
1749 QMetaObject::invokeMethod(object, "performGc");
1752 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1758 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1759 QCOMPARE(dtorCount, expectedDtorCount);
1763 void tst_qdeclarativeecmascript::regExpBug()
1765 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1766 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1767 QVERIFY(object != 0);
1768 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1772 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1774 QString functionSource = QLatin1String("(function(object) { return ") +
1775 QLatin1String(source) + QLatin1String(" })");
1777 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1780 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1781 if (function.IsEmpty())
1783 v8::Handle<v8::Value> args[] = { o };
1784 function->Call(engine->global(), 1, args);
1785 return tc.HasCaught();
1788 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1789 const char *source, v8::Handle<v8::Value> result)
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 };
1802 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1807 return value->StrictEquals(result);
1810 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1813 QString functionSource = QLatin1String("(function(object) { return ") +
1814 QLatin1String(source) + QLatin1String(" })");
1816 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1818 return v8::Handle<v8::Value>();
1819 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1820 if (function.IsEmpty())
1821 return v8::Handle<v8::Value>();
1822 v8::Handle<v8::Value> args[] = { o };
1824 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1827 return v8::Handle<v8::Value>();
1831 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1832 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1833 #define EVALUATE(source) evaluate(engine, object, source)
1835 void tst_qdeclarativeecmascript::callQtInvokables()
1837 MyInvokableObject o;
1839 QDeclarativeEngine qmlengine;
1840 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1842 QV8Engine *engine = ep->v8engine();
1844 v8::HandleScope handle_scope;
1845 v8::Context::Scope scope(engine->context());
1847 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1849 // Non-existent methods
1851 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1852 QCOMPARE(o.error(), false);
1853 QCOMPARE(o.invoked(), -1);
1854 QCOMPARE(o.actuals().count(), 0);
1857 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1858 QCOMPARE(o.error(), false);
1859 QCOMPARE(o.invoked(), -1);
1860 QCOMPARE(o.actuals().count(), 0);
1862 // Insufficient arguments
1864 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1865 QCOMPARE(o.error(), false);
1866 QCOMPARE(o.invoked(), -1);
1867 QCOMPARE(o.actuals().count(), 0);
1870 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1871 QCOMPARE(o.error(), false);
1872 QCOMPARE(o.invoked(), -1);
1873 QCOMPARE(o.actuals().count(), 0);
1875 // Excessive arguments
1877 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1878 QCOMPARE(o.error(), false);
1879 QCOMPARE(o.invoked(), 8);
1880 QCOMPARE(o.actuals().count(), 1);
1881 QCOMPARE(o.actuals().at(0), QVariant(10));
1884 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1885 QCOMPARE(o.error(), false);
1886 QCOMPARE(o.invoked(), 9);
1887 QCOMPARE(o.actuals().count(), 2);
1888 QCOMPARE(o.actuals().at(0), QVariant(10));
1889 QCOMPARE(o.actuals().at(1), QVariant(11));
1891 // Test return types
1893 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1894 QCOMPARE(o.error(), false);
1895 QCOMPARE(o.invoked(), 0);
1896 QCOMPARE(o.actuals().count(), 0);
1899 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1900 QCOMPARE(o.error(), false);
1901 QCOMPARE(o.invoked(), 1);
1902 QCOMPARE(o.actuals().count(), 0);
1905 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1906 QCOMPARE(o.error(), false);
1907 QCOMPARE(o.invoked(), 2);
1908 QCOMPARE(o.actuals().count(), 0);
1912 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1913 QVERIFY(!ret.IsEmpty());
1914 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1915 QCOMPARE(o.error(), false);
1916 QCOMPARE(o.invoked(), 3);
1917 QCOMPARE(o.actuals().count(), 0);
1922 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1923 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1924 QCOMPARE(o.error(), false);
1925 QCOMPARE(o.invoked(), 4);
1926 QCOMPARE(o.actuals().count(), 0);
1930 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1931 QCOMPARE(o.error(), false);
1932 QCOMPARE(o.invoked(), 5);
1933 QCOMPARE(o.actuals().count(), 0);
1937 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1938 QVERIFY(ret->IsString());
1939 QCOMPARE(engine->toString(ret), QString("Hello world"));
1940 QCOMPARE(o.error(), false);
1941 QCOMPARE(o.invoked(), 6);
1942 QCOMPARE(o.actuals().count(), 0);
1946 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1947 QCOMPARE(o.error(), false);
1948 QCOMPARE(o.invoked(), 7);
1949 QCOMPARE(o.actuals().count(), 0);
1953 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1954 QCOMPARE(o.error(), false);
1955 QCOMPARE(o.invoked(), 8);
1956 QCOMPARE(o.actuals().count(), 1);
1957 QCOMPARE(o.actuals().at(0), QVariant(94));
1960 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1961 QCOMPARE(o.error(), false);
1962 QCOMPARE(o.invoked(), 8);
1963 QCOMPARE(o.actuals().count(), 1);
1964 QCOMPARE(o.actuals().at(0), QVariant(94));
1967 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1968 QCOMPARE(o.error(), false);
1969 QCOMPARE(o.invoked(), 8);
1970 QCOMPARE(o.actuals().count(), 1);
1971 QCOMPARE(o.actuals().at(0), QVariant(0));
1974 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1975 QCOMPARE(o.error(), false);
1976 QCOMPARE(o.invoked(), 8);
1977 QCOMPARE(o.actuals().count(), 1);
1978 QCOMPARE(o.actuals().at(0), QVariant(0));
1981 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1982 QCOMPARE(o.error(), false);
1983 QCOMPARE(o.invoked(), 8);
1984 QCOMPARE(o.actuals().count(), 1);
1985 QCOMPARE(o.actuals().at(0), QVariant(0));
1988 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1989 QCOMPARE(o.error(), false);
1990 QCOMPARE(o.invoked(), 8);
1991 QCOMPARE(o.actuals().count(), 1);
1992 QCOMPARE(o.actuals().at(0), QVariant(0));
1995 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1996 QCOMPARE(o.error(), false);
1997 QCOMPARE(o.invoked(), 9);
1998 QCOMPARE(o.actuals().count(), 2);
1999 QCOMPARE(o.actuals().at(0), QVariant(122));
2000 QCOMPARE(o.actuals().at(1), QVariant(9));
2003 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2004 QCOMPARE(o.error(), false);
2005 QCOMPARE(o.invoked(), 10);
2006 QCOMPARE(o.actuals().count(), 1);
2007 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2010 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2011 QCOMPARE(o.error(), false);
2012 QCOMPARE(o.invoked(), 10);
2013 QCOMPARE(o.actuals().count(), 1);
2014 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2017 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2018 QCOMPARE(o.error(), false);
2019 QCOMPARE(o.invoked(), 10);
2020 QCOMPARE(o.actuals().count(), 1);
2021 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2024 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2025 QCOMPARE(o.error(), false);
2026 QCOMPARE(o.invoked(), 10);
2027 QCOMPARE(o.actuals().count(), 1);
2028 QCOMPARE(o.actuals().at(0), QVariant(0));
2031 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2032 QCOMPARE(o.error(), false);
2033 QCOMPARE(o.invoked(), 10);
2034 QCOMPARE(o.actuals().count(), 1);
2035 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2038 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2039 QCOMPARE(o.error(), false);
2040 QCOMPARE(o.invoked(), 10);
2041 QCOMPARE(o.actuals().count(), 1);
2042 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2045 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2046 QCOMPARE(o.error(), false);
2047 QCOMPARE(o.invoked(), 11);
2048 QCOMPARE(o.actuals().count(), 1);
2049 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2052 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2053 QCOMPARE(o.error(), false);
2054 QCOMPARE(o.invoked(), 11);
2055 QCOMPARE(o.actuals().count(), 1);
2056 QCOMPARE(o.actuals().at(0), QVariant("19"));
2060 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2061 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2062 QCOMPARE(o.error(), false);
2063 QCOMPARE(o.invoked(), 11);
2064 QCOMPARE(o.actuals().count(), 1);
2065 QCOMPARE(o.actuals().at(0), QVariant(expected));
2069 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", 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(QString()));
2076 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2077 QCOMPARE(o.error(), false);
2078 QCOMPARE(o.invoked(), 11);
2079 QCOMPARE(o.actuals().count(), 1);
2080 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2083 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2084 QCOMPARE(o.error(), false);
2085 QCOMPARE(o.invoked(), 12);
2086 QCOMPARE(o.actuals().count(), 1);
2087 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2090 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2091 QCOMPARE(o.error(), false);
2092 QCOMPARE(o.invoked(), 12);
2093 QCOMPARE(o.actuals().count(), 1);
2094 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2097 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2098 QCOMPARE(o.error(), false);
2099 QCOMPARE(o.invoked(), 12);
2100 QCOMPARE(o.actuals().count(), 1);
2101 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2104 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2105 QCOMPARE(o.error(), false);
2106 QCOMPARE(o.invoked(), 12);
2107 QCOMPARE(o.actuals().count(), 1);
2108 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2111 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2112 QCOMPARE(o.error(), false);
2113 QCOMPARE(o.invoked(), 12);
2114 QCOMPARE(o.actuals().count(), 1);
2115 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2118 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2119 QCOMPARE(o.error(), false);
2120 QCOMPARE(o.invoked(), 12);
2121 QCOMPARE(o.actuals().count(), 1);
2122 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2125 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2126 QCOMPARE(o.error(), false);
2127 QCOMPARE(o.invoked(), 13);
2128 QCOMPARE(o.actuals().count(), 1);
2129 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2132 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2133 QCOMPARE(o.error(), false);
2134 QCOMPARE(o.invoked(), 13);
2135 QCOMPARE(o.actuals().count(), 1);
2136 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2139 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2140 QCOMPARE(o.error(), false);
2141 QCOMPARE(o.invoked(), 13);
2142 QCOMPARE(o.actuals().count(), 1);
2143 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2146 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2147 QCOMPARE(o.error(), false);
2148 QCOMPARE(o.invoked(), 13);
2149 QCOMPARE(o.actuals().count(), 1);
2150 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2153 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2154 QCOMPARE(o.error(), false);
2155 QCOMPARE(o.invoked(), 13);
2156 QCOMPARE(o.actuals().count(), 1);
2157 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2160 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2161 QCOMPARE(o.error(), false);
2162 QCOMPARE(o.invoked(), 14);
2163 QCOMPARE(o.actuals().count(), 1);
2164 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2167 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2168 QCOMPARE(o.error(), false);
2169 QCOMPARE(o.invoked(), 14);
2170 QCOMPARE(o.actuals().count(), 1);
2171 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2174 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2175 QCOMPARE(o.error(), false);
2176 QCOMPARE(o.invoked(), 14);
2177 QCOMPARE(o.actuals().count(), 1);
2178 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2181 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2182 QCOMPARE(o.error(), false);
2183 QCOMPARE(o.invoked(), 14);
2184 QCOMPARE(o.actuals().count(), 1);
2185 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2188 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2189 QCOMPARE(o.error(), false);
2190 QCOMPARE(o.invoked(), 15);
2191 QCOMPARE(o.actuals().count(), 2);
2192 QCOMPARE(o.actuals().at(0), QVariant(4));
2193 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2196 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2197 QCOMPARE(o.error(), false);
2198 QCOMPARE(o.invoked(), 15);
2199 QCOMPARE(o.actuals().count(), 2);
2200 QCOMPARE(o.actuals().at(0), QVariant(8));
2201 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2204 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2205 QCOMPARE(o.error(), false);
2206 QCOMPARE(o.invoked(), 15);
2207 QCOMPARE(o.actuals().count(), 2);
2208 QCOMPARE(o.actuals().at(0), QVariant(3));
2209 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2212 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2213 QCOMPARE(o.error(), false);
2214 QCOMPARE(o.invoked(), 15);
2215 QCOMPARE(o.actuals().count(), 2);
2216 QCOMPARE(o.actuals().at(0), QVariant(44));
2217 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2220 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2221 QCOMPARE(o.error(), false);
2222 QCOMPARE(o.invoked(), -1);
2223 QCOMPARE(o.actuals().count(), 0);
2226 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2227 QCOMPARE(o.error(), false);
2228 QCOMPARE(o.invoked(), 16);
2229 QCOMPARE(o.actuals().count(), 1);
2230 QCOMPARE(o.actuals().at(0), QVariant(10));
2233 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2234 QCOMPARE(o.error(), false);
2235 QCOMPARE(o.invoked(), 17);
2236 QCOMPARE(o.actuals().count(), 2);
2237 QCOMPARE(o.actuals().at(0), QVariant(10));
2238 QCOMPARE(o.actuals().at(1), QVariant(11));
2241 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2242 QCOMPARE(o.error(), false);
2243 QCOMPARE(o.invoked(), 18);
2244 QCOMPARE(o.actuals().count(), 1);
2245 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2248 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2249 QCOMPARE(o.error(), false);
2250 QCOMPARE(o.invoked(), 19);
2251 QCOMPARE(o.actuals().count(), 1);
2252 QCOMPARE(o.actuals().at(0), QVariant(9));
2255 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2256 QCOMPARE(o.error(), false);
2257 QCOMPARE(o.invoked(), 20);
2258 QCOMPARE(o.actuals().count(), 2);
2259 QCOMPARE(o.actuals().at(0), QVariant(10));
2260 QCOMPARE(o.actuals().at(1), QVariant(19));
2263 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2264 QCOMPARE(o.error(), false);
2265 QCOMPARE(o.invoked(), 20);
2266 QCOMPARE(o.actuals().count(), 2);
2267 QCOMPARE(o.actuals().at(0), QVariant(10));
2268 QCOMPARE(o.actuals().at(1), QVariant(13));
2271 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2272 QCOMPARE(o.error(), false);
2273 QCOMPARE(o.invoked(), -3);
2274 QCOMPARE(o.actuals().count(), 1);
2275 QCOMPARE(o.actuals().at(0), QVariant(9));
2278 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2279 QCOMPARE(o.error(), false);
2280 QCOMPARE(o.invoked(), 21);
2281 QCOMPARE(o.actuals().count(), 2);
2282 QCOMPARE(o.actuals().at(0), QVariant(9));
2283 QCOMPARE(o.actuals().at(1), QVariant());
2286 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2287 QCOMPARE(o.error(), false);
2288 QCOMPARE(o.invoked(), 21);
2289 QCOMPARE(o.actuals().count(), 2);
2290 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2291 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2294 // QTBUG-13047 (check that you can pass registered object types as args)
2295 void tst_qdeclarativeecmascript::invokableObjectArg()
2297 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2299 QObject *o = component.create();
2301 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2303 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2308 // QTBUG-13047 (check that you can return registered object types from methods)
2309 void tst_qdeclarativeecmascript::invokableObjectRet()
2311 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2313 QObject *o = component.create();
2315 QCOMPARE(o->property("test").toBool(), true);
2320 void tst_qdeclarativeecmascript::listToVariant()
2322 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2324 MyQmlContainer container;
2326 QDeclarativeContext context(engine.rootContext());
2327 context.setContextObject(&container);
2329 QObject *object = component.create(&context);
2330 QVERIFY(object != 0);
2332 QVariant v = object->property("test");
2333 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2334 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2340 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2341 void tst_qdeclarativeecmascript::listAssignment()
2343 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2344 QObject *obj = component.create();
2345 QCOMPARE(obj->property("list1length").toInt(), 2);
2346 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2347 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2348 QCOMPARE(list1.count(&list1), list2.count(&list2));
2349 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2350 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2355 void tst_qdeclarativeecmascript::multiEngineObject()
2358 obj.setStringProperty("Howdy planet");
2360 QDeclarativeEngine e1;
2361 e1.rootContext()->setContextProperty("thing", &obj);
2362 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2364 QDeclarativeEngine e2;
2365 e2.rootContext()->setContextProperty("thing", &obj);
2366 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2368 QObject *o1 = c1.create();
2369 QObject *o2 = c2.create();
2371 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2372 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2378 // Test that references to QObjects are cleanup when the object is destroyed
2379 void tst_qdeclarativeecmascript::deletedObject()
2381 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2383 QObject *object = component.create();
2385 QCOMPARE(object->property("test1").toBool(), true);
2386 QCOMPARE(object->property("test2").toBool(), true);
2387 QCOMPARE(object->property("test3").toBool(), true);
2388 QCOMPARE(object->property("test4").toBool(), true);
2393 void tst_qdeclarativeecmascript::attachedPropertyScope()
2395 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2397 QObject *object = component.create();
2398 QVERIFY(object != 0);
2400 MyQmlAttachedObject *attached =
2401 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2402 QVERIFY(attached != 0);
2404 QCOMPARE(object->property("value2").toInt(), 0);
2406 attached->emitMySignal();
2408 QCOMPARE(object->property("value2").toInt(), 9);
2413 void tst_qdeclarativeecmascript::scriptConnect()
2416 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2418 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2419 QVERIFY(object != 0);
2421 QCOMPARE(object->property("test").toBool(), false);
2422 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2423 QCOMPARE(object->property("test").toBool(), true);
2429 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2431 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2432 QVERIFY(object != 0);
2434 QCOMPARE(object->property("test").toBool(), false);
2435 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2436 QCOMPARE(object->property("test").toBool(), true);
2442 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2444 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2445 QVERIFY(object != 0);
2447 QCOMPARE(object->property("test").toBool(), false);
2448 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2449 QCOMPARE(object->property("test").toBool(), true);
2455 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2457 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2458 QVERIFY(object != 0);
2460 QCOMPARE(object->methodCalled(), false);
2461 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2462 QCOMPARE(object->methodCalled(), true);
2468 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2470 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2471 QVERIFY(object != 0);
2473 QCOMPARE(object->methodCalled(), false);
2474 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2475 QCOMPARE(object->methodCalled(), true);
2481 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2483 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2484 QVERIFY(object != 0);
2486 QCOMPARE(object->property("test").toInt(), 0);
2487 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2488 QCOMPARE(object->property("test").toInt(), 2);
2494 void tst_qdeclarativeecmascript::scriptDisconnect()
2497 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2499 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2500 QVERIFY(object != 0);
2502 QCOMPARE(object->property("test").toInt(), 0);
2503 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2504 QCOMPARE(object->property("test").toInt(), 1);
2505 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2506 QCOMPARE(object->property("test").toInt(), 2);
2507 emit object->basicSignal();
2508 QCOMPARE(object->property("test").toInt(), 2);
2509 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2510 QCOMPARE(object->property("test").toInt(), 2);
2516 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2518 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2519 QVERIFY(object != 0);
2521 QCOMPARE(object->property("test").toInt(), 0);
2522 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2523 QCOMPARE(object->property("test").toInt(), 1);
2524 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2525 QCOMPARE(object->property("test").toInt(), 2);
2526 emit object->basicSignal();
2527 QCOMPARE(object->property("test").toInt(), 2);
2528 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2529 QCOMPARE(object->property("test").toInt(), 2);
2535 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2537 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2538 QVERIFY(object != 0);
2540 QCOMPARE(object->property("test").toInt(), 0);
2541 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2542 QCOMPARE(object->property("test").toInt(), 1);
2543 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2544 QCOMPARE(object->property("test").toInt(), 2);
2545 emit object->basicSignal();
2546 QCOMPARE(object->property("test").toInt(), 2);
2547 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2548 QCOMPARE(object->property("test").toInt(), 3);
2553 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2555 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2556 QVERIFY(object != 0);
2558 QCOMPARE(object->property("test").toInt(), 0);
2559 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2560 QCOMPARE(object->property("test").toInt(), 1);
2561 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2562 QCOMPARE(object->property("test").toInt(), 2);
2563 emit object->basicSignal();
2564 QCOMPARE(object->property("test").toInt(), 2);
2565 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2566 QCOMPARE(object->property("test").toInt(), 3);
2572 class OwnershipObject : public QObject
2576 OwnershipObject() { object = new QObject; }
2578 QPointer<QObject> object;
2581 QObject *getObject() { return object; }
2584 void tst_qdeclarativeecmascript::ownership()
2586 OwnershipObject own;
2587 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2588 context->setContextObject(&own);
2591 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2593 QVERIFY(own.object != 0);
2595 QObject *object = component.create(context);
2597 engine.collectGarbage();
2599 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2601 QVERIFY(own.object == 0);
2606 own.object = new QObject(&own);
2609 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2611 QVERIFY(own.object != 0);
2613 QObject *object = component.create(context);
2615 engine.collectGarbage();
2617 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2619 QVERIFY(own.object != 0);
2627 class CppOwnershipReturnValue : public QObject
2631 CppOwnershipReturnValue() : value(0) {}
2632 ~CppOwnershipReturnValue() { delete value; }
2634 Q_INVOKABLE QObject *create() {
2635 value = new QObject;
2636 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2640 Q_INVOKABLE MyQmlObject *createQmlObject() {
2641 MyQmlObject *rv = new MyQmlObject;
2646 QPointer<QObject> value;
2650 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2651 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2653 CppOwnershipReturnValue source;
2656 QDeclarativeEngine engine;
2657 engine.rootContext()->setContextProperty("source", &source);
2659 QVERIFY(source.value == 0);
2661 QDeclarativeComponent component(&engine);
2662 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2664 QObject *object = component.create();
2666 QVERIFY(object != 0);
2667 QVERIFY(source.value != 0);
2672 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2674 QVERIFY(source.value != 0);
2678 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2680 CppOwnershipReturnValue source;
2683 QDeclarativeEngine engine;
2684 engine.rootContext()->setContextProperty("source", &source);
2686 QVERIFY(source.value == 0);
2688 QDeclarativeComponent component(&engine);
2689 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2691 QObject *object = component.create();
2693 QVERIFY(object != 0);
2694 QVERIFY(source.value != 0);
2699 engine.collectGarbage();
2700 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2702 QVERIFY(source.value == 0);
2705 class QListQObjectMethodsObject : public QObject
2709 QListQObjectMethodsObject() {
2710 m_objects.append(new MyQmlObject());
2711 m_objects.append(new MyQmlObject());
2714 ~QListQObjectMethodsObject() {
2715 qDeleteAll(m_objects);
2719 QList<QObject *> getObjects() { return m_objects; }
2722 QList<QObject *> m_objects;
2725 // Tests that returning a QList<QObject*> from a method works
2726 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2728 QListQObjectMethodsObject obj;
2729 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2730 context->setContextObject(&obj);
2732 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2734 QObject *object = component.create(context);
2736 QCOMPARE(object->property("test").toInt(), 2);
2737 QCOMPARE(object->property("test2").toBool(), true);
2744 void tst_qdeclarativeecmascript::strictlyEquals()
2746 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2748 QObject *object = component.create();
2749 QVERIFY(object != 0);
2751 QCOMPARE(object->property("test1").toBool(), true);
2752 QCOMPARE(object->property("test2").toBool(), true);
2753 QCOMPARE(object->property("test3").toBool(), true);
2754 QCOMPARE(object->property("test4").toBool(), true);
2755 QCOMPARE(object->property("test5").toBool(), true);
2756 QCOMPARE(object->property("test6").toBool(), true);
2757 QCOMPARE(object->property("test7").toBool(), true);
2758 QCOMPARE(object->property("test8").toBool(), true);
2763 void tst_qdeclarativeecmascript::compiled()
2765 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2767 QObject *object = component.create();
2768 QVERIFY(object != 0);
2770 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2771 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2772 QCOMPARE(object->property("test3").toBool(), true);
2773 QCOMPARE(object->property("test4").toBool(), false);
2774 QCOMPARE(object->property("test5").toBool(), false);
2775 QCOMPARE(object->property("test6").toBool(), true);
2777 QCOMPARE(object->property("test7").toInt(), 185);
2778 QCOMPARE(object->property("test8").toInt(), 167);
2779 QCOMPARE(object->property("test9").toBool(), true);
2780 QCOMPARE(object->property("test10").toBool(), false);
2781 QCOMPARE(object->property("test11").toBool(), false);
2782 QCOMPARE(object->property("test12").toBool(), true);
2784 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2785 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2786 QCOMPARE(object->property("test15").toBool(), false);
2787 QCOMPARE(object->property("test16").toBool(), true);
2789 QCOMPARE(object->property("test17").toInt(), 5);
2790 QCOMPARE(object->property("test18").toReal(), qreal(176));
2791 QCOMPARE(object->property("test19").toInt(), 7);
2792 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2793 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2794 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2795 QCOMPARE(object->property("test23").toBool(), true);
2796 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2797 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2802 // Test that numbers assigned in bindings as strings work consistently
2803 void tst_qdeclarativeecmascript::numberAssignment()
2805 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2807 QObject *object = component.create();
2808 QVERIFY(object != 0);
2810 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2811 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2812 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2813 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2814 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2816 QCOMPARE(object->property("test5"), QVariant((int)7));
2817 QCOMPARE(object->property("test6"), QVariant((int)7));
2818 QCOMPARE(object->property("test7"), QVariant((int)6));
2819 QCOMPARE(object->property("test8"), QVariant((int)6));
2821 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2822 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2823 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2824 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2829 void tst_qdeclarativeecmascript::propertySplicing()
2831 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2833 QObject *object = component.create();
2834 QVERIFY(object != 0);
2836 QCOMPARE(object->property("test").toBool(), true);
2842 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2844 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2846 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2847 QVERIFY(object != 0);
2849 MyQmlObject::MyType type;
2850 type.value = 0x8971123;
2851 emit object->signalWithUnknownType(type);
2853 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2855 QCOMPARE(result.value, type.value);
2861 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2863 QTest::addColumn<QString>("expression");
2864 QTest::addColumn<QString>("compare");
2866 QString compareStrict("(function(a, b) { return a === b; })");
2867 QTest::newRow("true") << "true" << compareStrict;
2868 QTest::newRow("undefined") << "undefined" << compareStrict;
2869 QTest::newRow("null") << "null" << compareStrict;
2870 QTest::newRow("123") << "123" << compareStrict;
2871 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2873 QString comparePropertiesStrict(
2875 " if (typeof b != 'object')"
2877 " var props = Object.getOwnPropertyNames(b);"
2878 " for (var i = 0; i < props.length; ++i) {"
2879 " var p = props[i];"
2880 " return arguments.callee(a[p], b[p]);"
2883 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2884 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2887 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2889 QFETCH(QString, expression);
2890 QFETCH(QString, compare);
2892 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2893 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2894 QVERIFY(object != 0);
2896 QJSValue value = engine.evaluate(expression);
2897 QVERIFY(!engine.hasUncaughtException());
2898 object->setProperty("expression", expression);
2899 object->setProperty("compare", compare);
2900 object->setProperty("pass", false);
2902 emit object->signalWithVariant(QVariant::fromValue(value));
2903 QVERIFY(object->property("pass").toBool());
2906 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2908 signalWithJSValueInVariant_data();
2911 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2913 QFETCH(QString, expression);
2914 QFETCH(QString, compare);
2916 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2917 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2918 QVERIFY(object != 0);
2921 QJSValue value = engine2.evaluate(expression);
2922 QVERIFY(!engine2.hasUncaughtException());
2923 object->setProperty("expression", expression);
2924 object->setProperty("compare", compare);
2925 object->setProperty("pass", false);
2927 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2928 emit object->signalWithVariant(QVariant::fromValue(value));
2929 QVERIFY(!object->property("pass").toBool());
2932 void tst_qdeclarativeecmascript::moduleApi_data()
2934 QTest::addColumn<QUrl>("testfile");
2935 QTest::addColumn<QString>("errorMessage");
2936 QTest::addColumn<QStringList>("warningMessages");
2937 QTest::addColumn<QStringList>("readProperties");
2938 QTest::addColumn<QVariantList>("readExpectedValues");
2939 QTest::addColumn<QStringList>("writeProperties");
2940 QTest::addColumn<QVariantList>("writeValues");
2941 QTest::addColumn<QStringList>("readBackProperties");
2942 QTest::addColumn<QVariantList>("readBackExpectedValues");
2944 QTest::newRow("qobject, register + read + method")
2945 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2948 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2949 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2950 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2956 QTest::newRow("script, register + read")
2957 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2960 << (QStringList() << "scriptTest")
2961 << (QVariantList() << 13)
2967 QTest::newRow("qobject, caching + read")
2968 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2971 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2972 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2978 QTest::newRow("script, caching + read")
2979 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2982 << (QStringList() << "scriptTest")
2983 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2989 QTest::newRow("qobject, writing + readonly constraints")
2990 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2992 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2993 << (QStringList() << "readOnlyProperty" << "writableProperty")
2994 << (QVariantList() << 20 << 50)
2995 << (QStringList() << "firstProperty" << "writableProperty")
2996 << (QVariantList() << 30 << 30)
2997 << (QStringList() << "readOnlyProperty" << "writableProperty")
2998 << (QVariantList() << 20 << 30);
3000 QTest::newRow("script, writing + readonly constraints")
3001 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
3003 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3004 << (QStringList() << "readBack" << "unchanged")
3005 << (QVariantList() << 13 << 42)
3006 << (QStringList() << "firstProperty" << "secondProperty")
3007 << (QVariantList() << 30 << 30)
3008 << (QStringList() << "readBack" << "unchanged")
3009 << (QVariantList() << 30 << 42);
3011 QTest::newRow("qobject module API enum values in JS")
3012 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3015 << (QStringList() << "enumValue" << "enumMethod")
3016 << (QVariantList() << 42 << 30)
3022 QTest::newRow("qobject, invalid major version fail")
3023 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3024 << QString("QDeclarativeComponent: Component is not ready")
3033 QTest::newRow("qobject, invalid minor version fail")
3034 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3035 << QString("QDeclarativeComponent: Component is not ready")
3045 void tst_qdeclarativeecmascript::moduleApi()
3047 QFETCH(QUrl, testfile);
3048 QFETCH(QString, errorMessage);
3049 QFETCH(QStringList, warningMessages);
3050 QFETCH(QStringList, readProperties);
3051 QFETCH(QVariantList, readExpectedValues);
3052 QFETCH(QStringList, writeProperties);
3053 QFETCH(QVariantList, writeValues);
3054 QFETCH(QStringList, readBackProperties);
3055 QFETCH(QVariantList, readBackExpectedValues);
3057 QDeclarativeComponent component(&engine, testfile);
3059 if (!errorMessage.isEmpty())
3060 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3062 if (warningMessages.size())
3063 foreach (const QString &warning, warningMessages)
3064 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3066 QObject *object = component.create();
3067 if (!errorMessage.isEmpty()) {
3068 QVERIFY(object == 0);
3070 QVERIFY(object != 0);
3071 for (int i = 0; i < readProperties.size(); ++i)
3072 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3073 for (int i = 0; i < writeProperties.size(); ++i)
3074 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3075 for (int i = 0; i < readBackProperties.size(); ++i)
3076 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3081 void tst_qdeclarativeecmascript::importScripts_data()
3083 QTest::addColumn<QUrl>("testfile");
3084 QTest::addColumn<QString>("errorMessage");
3085 QTest::addColumn<QStringList>("warningMessages");
3086 QTest::addColumn<QStringList>("propertyNames");
3087 QTest::addColumn<QVariantList>("propertyValues");
3089 QTest::newRow("basic functionality")
3090 << TEST_FILE("jsimport/testImport.qml")
3093 << (QStringList() << QLatin1String("importedScriptStringValue")
3094 << QLatin1String("importedScriptFunctionValue")
3095 << QLatin1String("importedModuleAttachedPropertyValue")
3096 << QLatin1String("importedModuleEnumValue"))
3097 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3102 QTest::newRow("import scoping")
3103 << TEST_FILE("jsimport/testImportScoping.qml")
3106 << (QStringList() << QLatin1String("componentError"))
3107 << (QVariantList() << QVariant(5));
3109 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3110 << TEST_FILE("jsimportfail/failOne.qml")
3112 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3113 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3114 << (QVariantList() << QVariant(QString()));
3116 QTest::newRow("javascript imports in an import should be private to the import scope")
3117 << TEST_FILE("jsimportfail/failTwo.qml")
3119 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3120 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3121 << (QVariantList() << QVariant(QString()));
3123 QTest::newRow("module imports in an import should be private to the import scope")
3124 << TEST_FILE("jsimportfail/failThree.qml")
3126 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3127 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3128 << (QVariantList() << QVariant(false));
3130 QTest::newRow("typenames in an import should be private to the import scope")
3131 << TEST_FILE("jsimportfail/failFour.qml")
3133 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3134 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3135 << (QVariantList() << QVariant(0));
3137 QTest::newRow("import with imports has it's own activation scope")
3138 << TEST_FILE("jsimportfail/failFive.qml")
3140 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3141 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3142 << (QStringList() << QLatin1String("componentError"))
3143 << (QVariantList() << QVariant(0));
3145 QTest::newRow("import pragma library script")
3146 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3149 << (QStringList() << QLatin1String("testValue"))
3150 << (QVariantList() << QVariant(31));
3152 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3153 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3156 << (QStringList() << QLatin1String("testValue"))
3157 << (QVariantList() << QVariant(0));
3159 QTest::newRow("import pragma library script which has an import")
3160 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3163 << (QStringList() << QLatin1String("testValue"))
3164 << (QVariantList() << QVariant(55));
3166 QTest::newRow("import pragma library script which has a pragma library import")
3167 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3170 << (QStringList() << QLatin1String("testValue"))
3171 << (QVariantList() << QVariant(18));
3174 void tst_qdeclarativeecmascript::importScripts()
3176 QFETCH(QUrl, testfile);
3177 QFETCH(QString, errorMessage);
3178 QFETCH(QStringList, warningMessages);
3179 QFETCH(QStringList, propertyNames);
3180 QFETCH(QVariantList, propertyValues);
3182 QDeclarativeComponent component(&engine, testfile);
3184 if (!errorMessage.isEmpty())
3185 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3187 if (warningMessages.size())
3188 foreach (const QString &warning, warningMessages)
3189 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3191 QObject *object = component.create();
3192 if (!errorMessage.isEmpty()) {
3193 QVERIFY(object == 0);
3195 QVERIFY(object != 0);
3196 for (int i = 0; i < propertyNames.size(); ++i)
3197 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3202 void tst_qdeclarativeecmascript::scarceResources_other()
3204 /* These tests require knowledge of state, since we test values after
3205 performing signal or function invocation. */
3207 QPixmap origPixmap(100, 100);
3208 origPixmap.fill(Qt::blue);
3209 QString srp_name, expectedWarning;
3210 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3211 ScarceResourceObject *eo = 0;
3213 QObject *object = 0;
3215 /* property var semantics */
3217 // test that scarce resources are handled properly in signal invocation
3218 QDeclarativeComponent varComponentTen(&engine, TEST_FILE("scarceResourceSignal.var.qml"));
3219 object = varComponentTen.create();
3220 srsc = object->findChild<QObject*>("srsc");
3222 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3223 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3224 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3225 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3226 QMetaObject::invokeMethod(srsc, "testSignal");
3227 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3228 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3229 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3230 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3231 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3232 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3233 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3234 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3235 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3236 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3239 // test that scarce resources are handled properly from js functions in qml files
3240 QDeclarativeComponent varComponentEleven(&engine, TEST_FILE("scarceResourceFunction.var.qml"));
3241 object = varComponentEleven.create();
3242 QVERIFY(object != 0);
3243 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3244 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3245 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3246 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3247 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3248 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3249 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3250 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3251 QMetaObject::invokeMethod(object, "releaseScarceResource");
3252 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3253 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3254 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3255 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3258 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3259 QDeclarativeComponent varComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
3260 object = varComponentTwelve.create();
3261 QVERIFY(object != 0);
3262 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3263 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3264 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3265 srp_name = object->property("srp_name").toString();
3266 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3267 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3268 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3269 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3270 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3271 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3272 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3275 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3276 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3277 QDeclarativeComponent varComponentThirteen(&engine, TEST_FILE("scarceResourceObjectGc.var.qml"));
3278 object = varComponentThirteen.create();
3279 QVERIFY(object != 0);
3280 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3281 QMetaObject::invokeMethod(object, "assignVarProperty");
3282 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3283 QMetaObject::invokeMethod(object, "deassignVarProperty");
3284 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3287 /* property variant semantics */
3289 // test that scarce resources are handled properly in signal invocation
3290 QDeclarativeComponent variantComponentTen(&engine, TEST_FILE("scarceResourceSignal.variant.qml"));
3291 object = variantComponentTen.create();
3292 QVERIFY(object != 0);
3293 srsc = object->findChild<QObject*>("srsc");
3295 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3296 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3297 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3298 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3299 QMetaObject::invokeMethod(srsc, "testSignal");
3300 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3301 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3302 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3303 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3304 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3305 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3306 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3307 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3308 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3309 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3312 // test that scarce resources are handled properly from js functions in qml files
3313 QDeclarativeComponent variantComponentEleven(&engine, TEST_FILE("scarceResourceFunction.variant.qml"));
3314 object = variantComponentEleven.create();
3315 QVERIFY(object != 0);
3316 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3317 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3318 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3319 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3320 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3321 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3322 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3323 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3324 QMetaObject::invokeMethod(object, "releaseScarceResource");
3325 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3326 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3327 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3328 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3331 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3332 QDeclarativeComponent variantComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.variant.qml"));
3333 object = variantComponentTwelve.create();
3334 QVERIFY(object != 0);
3335 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3336 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3337 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3338 srp_name = object->property("srp_name").toString();
3339 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3340 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3341 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3342 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3343 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3344 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3345 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3349 void tst_qdeclarativeecmascript::scarceResources_data()
3351 QTest::addColumn<QUrl>("qmlFile");
3352 QTest::addColumn<bool>("readDetachStatus");
3353 QTest::addColumn<bool>("expectedDetachStatus");
3354 QTest::addColumn<QStringList>("propertyNames");
3355 QTest::addColumn<QVariantList>("expectedValidity");
3356 QTest::addColumn<QVariantList>("expectedValues");
3357 QTest::addColumn<QStringList>("expectedErrors");
3359 QPixmap origPixmap(100, 100);
3360 origPixmap.fill(Qt::blue);
3362 /* property var semantics */
3364 // in the following three cases, the instance created from the component
3365 // has a property which is a copy of the scarce resource; hence, the
3366 // resource should NOT be detached prior to deletion of the object instance,
3367 // unless the resource is destroyed explicitly.
3368 QTest::newRow("var: import scarce resource copy directly")
3369 << TEST_FILE("scarceResourceCopy.var.qml")
3371 << false // won't be detached, because assigned to property and not explicitly released
3372 << (QStringList() << QLatin1String("scarceResourceCopy"))
3373 << (QList<QVariant>() << true)
3374 << (QList<QVariant>() << origPixmap)
3377 QTest::newRow("var: import scarce resource copy from JS")
3378 << TEST_FILE("scarceResourceCopyFromJs.var.qml")
3380 << false // won't be detached, because assigned to property and not explicitly released
3381 << (QStringList() << QLatin1String("scarceResourceCopy"))
3382 << (QList<QVariant>() << true)
3383 << (QList<QVariant>() << origPixmap)
3386 QTest::newRow("var: import released scarce resource copy from JS")
3387 << TEST_FILE("scarceResourceDestroyedCopy.var.qml")
3389 << true // explicitly released, so it will be detached
3390 << (QStringList() << QLatin1String("scarceResourceCopy"))
3391 << (QList<QVariant>() << false)
3392 << (QList<QVariant>() << QVariant())
3395 // in the following three cases, no other copy should exist in memory,
3396 // and so it should be detached (unless explicitly preserved).
3397 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3398 << TEST_FILE("scarceResourceTest.var.qml")
3400 << true // auto released, so it will be detached
3401 << (QStringList() << QLatin1String("scarceResourceTest"))
3402 << (QList<QVariant>() << true)
3403 << (QList<QVariant>() << QVariant(100))
3405 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3406 << TEST_FILE("scarceResourceTestPreserve.var.qml")
3408 << false // won't be detached because we explicitly preserve it
3409 << (QStringList() << QLatin1String("scarceResourceTest"))
3410 << (QList<QVariant>() << true)
3411 << (QList<QVariant>() << QVariant(100))
3413 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3414 << TEST_FILE("scarceResourceTestMultiple.var.qml")
3416 << true // will be detached because all resources were released manually or automatically.
3417 << (QStringList() << QLatin1String("scarceResourceTest"))
3418 << (QList<QVariant>() << true)
3419 << (QList<QVariant>() << QVariant(100))
3422 // In the following three cases, test that scarce resources are handled
3423 // correctly for imports.
3424 QTest::newRow("var: import with no binding")
3425 << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
3426 << false // cannot check detach status.
3429 << QList<QVariant>()
3430 << QList<QVariant>()
3432 QTest::newRow("var: import with binding without explicit preserve")
3433 << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
3436 << (QStringList() << QLatin1String("scarceResourceCopy"))
3437 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3438 << (QList<QVariant>() << QVariant())
3440 QTest::newRow("var: import with explicit release after binding evaluation")
3441 << TEST_FILE("scarceResourceCopyImport.var.qml")
3444 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3445 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3446 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3448 QTest::newRow("var: import with different js objects")
3449 << TEST_FILE("scarceResourceCopyImportDifferent.var.qml")
3452 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3453 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3454 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3456 QTest::newRow("var: import with different js objects and explicit release")
3457 << TEST_FILE("scarceResourceMultipleDifferentNoBinding.var.qml")
3460 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3461 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3462 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3464 QTest::newRow("var: import with same js objects and explicit release")
3465 << TEST_FILE("scarceResourceMultipleSameNoBinding.var.qml")
3468 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3469 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3470 << (QList<QVariant>() << QVariant() << QVariant())
3472 QTest::newRow("var: binding with same js objects and explicit release")
3473 << TEST_FILE("scarceResourceMultipleSameWithBinding.var.qml")
3476 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3477 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3478 << (QList<QVariant>() << QVariant() << QVariant())
3482 /* property variant semantics */
3484 // in the following three cases, the instance created from the component
3485 // has a property which is a copy of the scarce resource; hence, the
3486 // resource should NOT be detached prior to deletion of the object instance,
3487 // unless the resource is destroyed explicitly.
3488 QTest::newRow("variant: import scarce resource copy directly")
3489 << TEST_FILE("scarceResourceCopy.variant.qml")
3491 << false // won't be detached, because assigned to property and not explicitly released
3492 << (QStringList() << QLatin1String("scarceResourceCopy"))
3493 << (QList<QVariant>() << true)
3494 << (QList<QVariant>() << origPixmap)
3497 QTest::newRow("variant: import scarce resource copy from JS")
3498 << TEST_FILE("scarceResourceCopyFromJs.variant.qml")
3500 << false // won't be detached, because assigned to property and not explicitly released
3501 << (QStringList() << QLatin1String("scarceResourceCopy"))
3502 << (QList<QVariant>() << true)
3503 << (QList<QVariant>() << origPixmap)
3506 QTest::newRow("variant: import released scarce resource copy from JS")
3507 << TEST_FILE("scarceResourceDestroyedCopy.variant.qml")
3509 << true // explicitly released, so it will be detached
3510 << (QStringList() << QLatin1String("scarceResourceCopy"))
3511 << (QList<QVariant>() << false)
3512 << (QList<QVariant>() << QVariant())
3515 // in the following three cases, no other copy should exist in memory,
3516 // and so it should be detached (unless explicitly preserved).
3517 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3518 << TEST_FILE("scarceResourceTest.variant.qml")
3520 << true // auto released, so it will be detached
3521 << (QStringList() << QLatin1String("scarceResourceTest"))
3522 << (QList<QVariant>() << true)
3523 << (QList<QVariant>() << QVariant(100))
3525 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3526 << TEST_FILE("scarceResourceTestPreserve.variant.qml")
3528 << false // won't be detached because we explicitly preserve it
3529 << (QStringList() << QLatin1String("scarceResourceTest"))
3530 << (QList<QVariant>() << true)
3531 << (QList<QVariant>() << QVariant(100))
3533 QTest::newRow("variant: import multiple scarce resources")
3534 << TEST_FILE("scarceResourceTestMultiple.variant.qml")
3536 << true // will be detached because all resources were released manually or automatically.
3537 << (QStringList() << QLatin1String("scarceResourceTest"))
3538 << (QList<QVariant>() << true)
3539 << (QList<QVariant>() << QVariant(100))
3542 // In the following three cases, test that scarce resources are handled
3543 // correctly for imports.
3544 QTest::newRow("variant: import with no binding")
3545 << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
3546 << false // cannot check detach status.
3549 << QList<QVariant>()
3550 << QList<QVariant>()
3552 QTest::newRow("variant: import with binding without explicit preserve")
3553 << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
3556 << (QStringList() << QLatin1String("scarceResourceCopy"))
3557 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3558 << (QList<QVariant>() << QVariant())
3560 QTest::newRow("variant: import with explicit release after binding evaluation")
3561 << TEST_FILE("scarceResourceCopyImport.variant.qml")
3564 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3565 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3566 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3570 void tst_qdeclarativeecmascript::scarceResources()
3572 QFETCH(QUrl, qmlFile);
3573 QFETCH(bool, readDetachStatus);
3574 QFETCH(bool, expectedDetachStatus);
3575 QFETCH(QStringList, propertyNames);
3576 QFETCH(QVariantList, expectedValidity);
3577 QFETCH(QVariantList, expectedValues);
3578 QFETCH(QStringList, expectedErrors);
3580 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3581 ScarceResourceObject *eo = 0;
3582 QObject *object = 0;
3584 QDeclarativeComponent c(&engine, qmlFile);
3585 object = c.create();
3586 QVERIFY(object != 0);
3587 for (int i = 0; i < propertyNames.size(); ++i) {
3588 QString prop = propertyNames.at(i);
3589 bool validity = expectedValidity.at(i).toBool();
3590 QVariant value = expectedValues.at(i);
3592 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3593 if (value.type() == QVariant::Int) {
3594 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3595 } else if (value.type() == QVariant::Pixmap) {
3596 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3600 if (readDetachStatus) {
3601 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3602 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3605 QVERIFY(ep->scarceResources.isEmpty());
3609 void tst_qdeclarativeecmascript::propertyChangeSlots()
3611 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3612 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3613 QObject *object = component.create();
3614 QVERIFY(object != 0);
3617 // ensure that invalid property names fail properly.
3618 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3619 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3620 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3621 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3622 object = e1.create();
3623 QVERIFY(object == 0);
3626 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3627 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3628 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3629 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3630 object = e2.create();
3631 QVERIFY(object == 0);
3634 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3635 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3636 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3637 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3638 object = e3.create();
3639 QVERIFY(object == 0);
3642 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3643 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3644 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3645 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3646 object = e4.create();
3647 QVERIFY(object == 0);
3651 void tst_qdeclarativeecmascript::propertyVar_data()
3653 QTest::addColumn<QUrl>("qmlFile");
3656 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3657 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3658 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3659 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3660 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3661 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3662 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3663 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3664 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3667 void tst_qdeclarativeecmascript::propertyVar()
3669 QFETCH(QUrl, qmlFile);
3671 QDeclarativeComponent component(&engine, qmlFile);
3672 QObject *object = component.create();
3673 QVERIFY(object != 0);
3675 QCOMPARE(object->property("test").toBool(), true);
3680 // Tests that we can write QVariant values to var properties from C++
3681 void tst_qdeclarativeecmascript::propertyVarCpp()
3683 QObject *object = 0;
3685 // ensure that writing to and reading from a var property from cpp works as required.
3686 // Literal values stored in var properties can be read and written as QVariants
3687 // of a specific type, whereas object values are read as QVariantMaps.
3688 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3689 object = component.create();
3690 QVERIFY(object != 0);
3691 // assign int to property var that currently has int assigned
3692 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3693 QCOMPARE(object->property("varBound"), QVariant(15));
3694 QCOMPARE(object->property("intBound"), QVariant(15));
3695 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3696 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3697 // assign string to property var that current has bool assigned
3698 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3699 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3700 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3701 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3702 // now enforce behaviour when accessing JavaScript objects from cpp.
3703 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3707 static void gc(QDeclarativeEngine &engine)
3709 engine.collectGarbage();
3710 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3713 void tst_qdeclarativeecmascript::propertyVarOwnership()
3715 // Referenced JS objects are not collected
3717 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3718 QObject *object = component.create();
3719 QVERIFY(object != 0);
3720 QCOMPARE(object->property("test").toBool(), false);
3721 QMetaObject::invokeMethod(object, "runTest");
3722 QCOMPARE(object->property("test").toBool(), true);
3725 // Referenced JS objects are not collected
3727 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3728 QObject *object = component.create();
3729 QVERIFY(object != 0);
3730 QCOMPARE(object->property("test").toBool(), false);
3731 QMetaObject::invokeMethod(object, "runTest");
3732 QCOMPARE(object->property("test").toBool(), true);
3735 // Qt objects are not collected until they've been dereferenced
3737 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3738 QObject *object = component.create();
3739 QVERIFY(object != 0);
3741 QCOMPARE(object->property("test2").toBool(), false);
3742 QCOMPARE(object->property("test2").toBool(), false);
3744 QMetaObject::invokeMethod(object, "runTest");
3745 QCOMPARE(object->property("test1").toBool(), true);
3747 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3748 QVERIFY(!referencedObject.isNull());
3750 QVERIFY(!referencedObject.isNull());
3752 QMetaObject::invokeMethod(object, "runTest2");
3753 QCOMPARE(object->property("test2").toBool(), true);
3755 QVERIFY(referencedObject.isNull());
3759 // Self reference does not prevent Qt object collection
3761 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3762 QObject *object = component.create();
3763 QVERIFY(object != 0);
3765 QCOMPARE(object->property("test").toBool(), true);
3767 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3768 QVERIFY(!referencedObject.isNull());
3770 QVERIFY(!referencedObject.isNull());
3772 QMetaObject::invokeMethod(object, "runTest");
3774 QVERIFY(referencedObject.isNull());
3780 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3782 // The childObject has a reference to a different QObject. We want to ensure
3783 // that the different item will not be cleaned up until required. IE, the childObject
3784 // has implicit ownership of the constructed QObject.
3785 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3786 QObject *object = component.create();
3787 QVERIFY(object != 0);
3788 QMetaObject::invokeMethod(object, "assignCircular");
3789 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3790 QObject *rootObject = object->property("vp").value<QObject*>();
3791 QVERIFY(rootObject != 0);
3792 QObject *childObject = rootObject->findChild<QObject*>("text");
3793 QVERIFY(childObject != 0);
3794 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3795 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3796 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3797 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3798 QVERIFY(!qobjectGuard.isNull());
3799 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3800 QVERIFY(!qobjectGuard.isNull());
3801 QMetaObject::invokeMethod(object, "deassignCircular");
3802 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3803 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3807 void tst_qdeclarativeecmascript::propertyVarReparent()
3809 // ensure that nothing breaks if we re-parent objects
3810 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3811 QObject *object = component.create();
3812 QVERIFY(object != 0);
3813 QMetaObject::invokeMethod(object, "assignVarProp");
3814 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3815 QObject *rect = object->property("vp").value<QObject*>();
3816 QObject *text = rect->findChild<QObject*>("textOne");
3817 QObject *text2 = rect->findChild<QObject*>("textTwo");
3818 QWeakPointer<QObject> rectGuard(rect);
3819 QWeakPointer<QObject> textGuard(text);
3820 QWeakPointer<QObject> text2Guard(text2);
3821 QVERIFY(!rectGuard.isNull());
3822 QVERIFY(!textGuard.isNull());
3823 QVERIFY(!text2Guard.isNull());
3824 QCOMPARE(text->property("textCanary").toInt(), 11);
3825 QCOMPARE(text2->property("textCanary").toInt(), 12);
3826 // now construct an image which we will reparent.
3827 QMetaObject::invokeMethod(text2, "constructQObject");
3828 QObject *image = text2->property("vp").value<QObject*>();
3829 QWeakPointer<QObject> imageGuard(image);
3830 QVERIFY(!imageGuard.isNull());
3831 QCOMPARE(image->property("imageCanary").toInt(), 13);
3832 // now reparent the "Image" object (currently, it has JS ownership)
3833 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3834 QMetaObject::invokeMethod(text2, "deassignVp");
3835 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3836 QCOMPARE(text->property("textCanary").toInt(), 11);
3837 QCOMPARE(text2->property("textCanary").toInt(), 22);
3838 QVERIFY(!imageGuard.isNull()); // should still be alive.
3839 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3840 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3841 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3842 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3846 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3848 // sometimes reparenting can cause problems
3849 // (eg, if the ctxt is collected, varproperties are no longer available)
3850 // this test ensures that no crash occurs in that situation.
3851 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3852 QObject *object = component.create();
3853 QVERIFY(object != 0);
3854 QMetaObject::invokeMethod(object, "assignVarProp");
3855 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3856 QObject *rect = object->property("vp").value<QObject*>();
3857 QObject *text = rect->findChild<QObject*>("textOne");
3858 QObject *text2 = rect->findChild<QObject*>("textTwo");
3859 QWeakPointer<QObject> rectGuard(rect);
3860 QWeakPointer<QObject> textGuard(text);
3861 QWeakPointer<QObject> text2Guard(text2);
3862 QVERIFY(!rectGuard.isNull());
3863 QVERIFY(!textGuard.isNull());
3864 QVERIFY(!text2Guard.isNull());
3865 QCOMPARE(text->property("textCanary").toInt(), 11);
3866 QCOMPARE(text2->property("textCanary").toInt(), 12);
3867 // now construct an image which we will reparent.
3868 QMetaObject::invokeMethod(text2, "constructQObject");
3869 QObject *image = text2->property("vp").value<QObject*>();
3870 QWeakPointer<QObject> imageGuard(image);
3871 QVERIFY(!imageGuard.isNull());
3872 QCOMPARE(image->property("imageCanary").toInt(), 13);
3873 // now reparent the "Image" object (currently, it has JS ownership)
3874 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3875 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3876 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3877 QVERIFY(!imageGuard.isNull()); // should still be alive.
3878 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3880 QVERIFY(imageGuard.isNull()); // should now be dead.
3883 void tst_qdeclarativeecmascript::propertyVarCircular()
3885 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3886 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3887 QObject *object = component.create();
3888 QVERIFY(object != 0);
3889 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3890 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3891 QCOMPARE(object->property("canaryInt"), QVariant(5));
3892 QVariant canaryResourceVariant = object->property("canaryResource");
3893 QVERIFY(canaryResourceVariant.isValid());
3894 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3895 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3896 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3897 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3898 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3899 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3900 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3901 QCOMPARE(object->property("canaryInt"), QVariant(2));
3902 QCOMPARE(object->property("canaryResource"), QVariant(1));
3903 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3907 void tst_qdeclarativeecmascript::propertyVarCircular2()
3909 // track deletion of JS-owned parent item with Cpp-owned child
3910 // where the child has a var property referencing its parent.
3911 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3912 QObject *object = component.create();
3913 QVERIFY(object != 0);
3914 QMetaObject::invokeMethod(object, "assignCircular");
3915 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3916 QObject *rootObject = object->property("vp").value<QObject*>();
3917 QVERIFY(rootObject != 0);
3918 QObject *childObject = rootObject->findChild<QObject*>("text");
3919 QVERIFY(childObject != 0);
3920 QWeakPointer<QObject> rootObjectTracker(rootObject);
3921 QVERIFY(!rootObjectTracker.isNull());
3922 QWeakPointer<QObject> childObjectTracker(childObject);
3923 QVERIFY(!childObjectTracker.isNull());
3925 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3926 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3927 QMetaObject::invokeMethod(object, "deassignCircular");
3928 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3929 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3930 QVERIFY(childObjectTracker.isNull()); // should have been collected
3934 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3936 *(int*)(parameter) += 1;
3937 qPersistentDispose(object);
3940 void tst_qdeclarativeecmascript::propertyVarInheritance()
3942 int propertyVarWeakRefCallbackCount = 0;
3944 // enforce behaviour regarding element inheritance - ensure handle disposal.
3945 // The particular component under test here has a chain of references.
3946 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3947 QObject *object = component.create();
3948 QVERIFY(object != 0);
3949 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3950 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3951 // we want to be able to track when the varProperties array of the last metaobject is disposed
3952 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3953 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*>();
3954 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3955 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3956 v8::Persistent<v8::Value> icoCanaryHandle;
3957 v8::Persistent<v8::Value> ccoCanaryHandle;
3960 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3961 // public function which can return us a handle to something in the varProperties array.
3962 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3963 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3964 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3965 // as the varproperties array of each vmemo still references the resource.
3966 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3967 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3969 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3971 // now we deassign the var prop, which should trigger collection of item subtrees.
3972 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3973 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3974 // ensure that there are only weak handles to the underlying varProperties array remaining.
3976 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3978 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3979 // to what remains are weak, all varProperties arrays must have been collected.
3982 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3984 int propertyVarWeakRefCallbackCount = 0;
3986 // The particular component under test here does NOT have a chain of references; the
3987 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3988 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3989 QObject *object = component.create();
3990 QVERIFY(object != 0);
3991 QMetaObject::invokeMethod(object, "assignCircular");
3992 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3993 QObject *rootObject = object->property("vp").value<QObject*>();
3994 QVERIFY(rootObject != 0);
3995 QObject *childObject = rootObject->findChild<QObject*>("text");
3996 QVERIFY(childObject != 0);
3997 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3998 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3999 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4002 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4003 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
4004 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4006 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4007 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4009 QMetaObject::invokeMethod(object, "deassignCircular");
4010 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4011 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4015 // Ensure that QObject type conversion works on binding assignment
4016 void tst_qdeclarativeecmascript::elementAssign()
4018 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
4020 QObject *object = component.create();
4021 QVERIFY(object != 0);
4023 QCOMPARE(object->property("test").toBool(), true);
4029 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4031 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
4033 QObject *object = component.create();
4034 QVERIFY(object != 0);
4036 QCOMPARE(object->property("test").toBool(), true);
4042 void tst_qdeclarativeecmascript::objectConversion()
4044 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
4046 QObject *object = component.create();
4047 QVERIFY(object != 0);
4049 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4050 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4057 void tst_qdeclarativeecmascript::booleanConversion()
4059 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
4061 QObject *object = component.create();
4062 QVERIFY(object != 0);
4064 QCOMPARE(object->property("test_true1").toBool(), true);
4065 QCOMPARE(object->property("test_true2").toBool(), true);
4066 QCOMPARE(object->property("test_true3").toBool(), true);
4067 QCOMPARE(object->property("test_true4").toBool(), true);
4068 QCOMPARE(object->property("test_true5").toBool(), true);
4070 QCOMPARE(object->property("test_false1").toBool(), false);
4071 QCOMPARE(object->property("test_false2").toBool(), false);
4072 QCOMPARE(object->property("test_false3").toBool(), false);
4077 void tst_qdeclarativeecmascript::handleReferenceManagement()
4082 // Linear QObject reference
4083 QDeclarativeEngine hrmEngine;
4084 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
4085 QObject *object = component.create();
4086 QVERIFY(object != 0);
4087 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4088 cro->setDtorCount(&dtorCount);
4089 QMetaObject::invokeMethod(object, "createReference");
4091 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4093 hrmEngine.collectGarbage();
4094 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4095 QCOMPARE(dtorCount, 3);
4100 // Circular QObject reference
4101 QDeclarativeEngine hrmEngine;
4102 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
4103 QObject *object = component.create();
4104 QVERIFY(object != 0);
4105 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4106 cro->setDtorCount(&dtorCount);
4107 QMetaObject::invokeMethod(object, "circularReference");
4109 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4111 hrmEngine.collectGarbage();
4112 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4113 QCOMPARE(dtorCount, 3);
4118 // Linear handle reference
4119 QDeclarativeEngine hrmEngine;
4120 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4121 QObject *object = component.create();
4122 QVERIFY(object != 0);
4123 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4125 crh->setDtorCount(&dtorCount);
4126 QMetaObject::invokeMethod(object, "createReference");
4127 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4128 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4129 QVERIFY(first != 0);
4130 QVERIFY(second != 0);
4131 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4132 // now we have to reparent second and make second owned by JS.
4133 second->setParent(0);
4134 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4136 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4138 hrmEngine.collectGarbage();
4139 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4140 QCOMPARE(dtorCount, 3);
4145 // Circular handle reference
4146 QDeclarativeEngine hrmEngine;
4147 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
4148 QObject *object = component.create();
4149 QVERIFY(object != 0);
4150 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4152 crh->setDtorCount(&dtorCount);
4153 QMetaObject::invokeMethod(object, "circularReference");
4154 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4155 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4156 QVERIFY(first != 0);
4157 QVERIFY(second != 0);
4158 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4159 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4160 // now we have to reparent and change ownership.
4161 first->setParent(0);
4162 second->setParent(0);
4163 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4164 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4166 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4168 hrmEngine.collectGarbage();
4169 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4170 QCOMPARE(dtorCount, 3);
4175 // multiple engine interaction - linear reference
4176 QDeclarativeEngine hrmEngine1;
4177 QDeclarativeEngine hrmEngine2;
4178 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4179 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4180 QObject *object1 = component1.create();
4181 QObject *object2 = component2.create();
4182 QVERIFY(object1 != 0);
4183 QVERIFY(object2 != 0);
4184 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4185 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4188 crh1->setDtorCount(&dtorCount);
4189 crh2->setDtorCount(&dtorCount);
4190 QMetaObject::invokeMethod(object1, "createReference");
4191 QMetaObject::invokeMethod(object2, "createReference");
4192 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4193 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4194 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4195 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4196 QVERIFY(first1 != 0);
4197 QVERIFY(second1 != 0);
4198 QVERIFY(first2 != 0);
4199 QVERIFY(second2 != 0);
4200 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4201 // now we have to reparent second2 and make second2 owned by JS.
4202 second2->setParent(0);
4203 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4205 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4206 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4209 hrmEngine1.collectGarbage();
4210 hrmEngine2.collectGarbage();
4211 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4212 QCOMPARE(dtorCount, 6);
4217 // multiple engine interaction - circular reference
4218 QDeclarativeEngine hrmEngine1;
4219 QDeclarativeEngine hrmEngine2;
4220 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4221 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4222 QObject *object1 = component1.create();
4223 QObject *object2 = component2.create();
4224 QVERIFY(object1 != 0);
4225 QVERIFY(object2 != 0);
4226 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4227 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4230 crh1->setDtorCount(&dtorCount);
4231 crh2->setDtorCount(&dtorCount);
4232 QMetaObject::invokeMethod(object1, "createReference");
4233 QMetaObject::invokeMethod(object2, "createReference");
4234 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4235 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4236 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4237 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4238 QVERIFY(first1 != 0);
4239 QVERIFY(second1 != 0);
4240 QVERIFY(first2 != 0);
4241 QVERIFY(second2 != 0);
4242 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4243 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4244 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4245 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4246 // now we have to reparent and change ownership to JS.
4247 first1->setParent(0);
4248 second1->setParent(0);
4249 first2->setParent(0);
4250 second2->setParent(0);
4251 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4252 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4253 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4254 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4256 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4257 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4260 hrmEngine1.collectGarbage();
4261 hrmEngine2.collectGarbage();
4262 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4263 QCOMPARE(dtorCount, 6);
4268 // multiple engine interaction - linear reference with engine deletion
4269 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4270 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4271 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4272 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4273 QObject *object1 = component1.create();
4274 QObject *object2 = component2.create();
4275 QVERIFY(object1 != 0);
4276 QVERIFY(object2 != 0);
4277 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4278 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4281 crh1->setDtorCount(&dtorCount);
4282 crh2->setDtorCount(&dtorCount);
4283 QMetaObject::invokeMethod(object1, "createReference");
4284 QMetaObject::invokeMethod(object2, "createReference");
4285 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4286 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4287 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4288 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4289 QVERIFY(first1 != 0);
4290 QVERIFY(second1 != 0);
4291 QVERIFY(first2 != 0);
4292 QVERIFY(second2 != 0);
4293 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4294 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4295 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4296 // now we have to reparent and change ownership to JS.
4297 first1->setParent(crh1);
4298 second1->setParent(0);
4299 first2->setParent(0);
4300 second2->setParent(0);
4301 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4302 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4303 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4305 QCOMPARE(dtorCount, 0);
4308 QCOMPARE(dtorCount, 0);
4311 hrmEngine1->collectGarbage();
4312 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4313 QCOMPARE(dtorCount, 6);
4318 void tst_qdeclarativeecmascript::stringArg()
4320 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4321 QObject *object = component.create();
4322 QVERIFY(object != 0);
4323 QMetaObject::invokeMethod(object, "success");
4324 QVERIFY(object->property("returnValue").toBool());
4326 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4327 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4328 QMetaObject::invokeMethod(object, "failure");
4329 QVERIFY(object->property("returnValue").toBool());
4334 void tst_qdeclarativeecmascript::readonlyDeclaration()
4336 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4338 QObject *object = component.create();
4339 QVERIFY(object != 0);
4341 QCOMPARE(object->property("test").toBool(), true);
4346 Q_DECLARE_METATYPE(QList<int>)
4347 Q_DECLARE_METATYPE(QList<qreal>)
4348 Q_DECLARE_METATYPE(QList<bool>)
4349 Q_DECLARE_METATYPE(QList<QString>)
4350 Q_DECLARE_METATYPE(QList<QUrl>)
4351 void tst_qdeclarativeecmascript::sequenceConversionRead()
4354 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4355 QDeclarativeComponent component(&engine, qmlFile);
4356 QObject *object = component.create();
4357 QVERIFY(object != 0);
4358 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4361 QMetaObject::invokeMethod(object, "readSequences");
4362 QList<int> intList; intList << 1 << 2 << 3 << 4;
4363 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4364 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4365 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4366 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4367 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4368 QList<bool> boolList; boolList << true << false << true << false;
4369 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4370 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4371 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4372 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4373 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4374 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4375 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4376 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4377 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4378 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4379 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4381 QMetaObject::invokeMethod(object, "readSequenceElements");
4382 QCOMPARE(object->property("intVal").toInt(), 2);
4383 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4384 QCOMPARE(object->property("boolVal").toBool(), false);
4385 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4386 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4387 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4389 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4390 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4392 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4393 QDeclarativeProperty seqProp(seq, "intListProperty");
4394 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4395 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4396 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4398 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4399 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4405 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4406 QDeclarativeComponent component(&engine, qmlFile);
4407 QObject *object = component.create();
4408 QVERIFY(object != 0);
4409 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4412 // we haven't registered QList<QPoint> as a sequence type.
4413 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4414 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4415 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4416 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4418 QMetaObject::invokeMethod(object, "performTest");
4420 // QList<QPoint> has not been registered as a sequence type.
4421 QCOMPARE(object->property("pointListLength").toInt(), 0);
4422 QVERIFY(!object->property("pointList").isValid());
4423 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4424 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4425 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4431 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4434 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4435 QDeclarativeComponent component(&engine, qmlFile);
4436 QObject *object = component.create();
4437 QVERIFY(object != 0);
4438 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4441 QMetaObject::invokeMethod(object, "writeSequences");
4442 QCOMPARE(object->property("success").toBool(), true);
4444 QMetaObject::invokeMethod(object, "writeSequenceElements");
4445 QCOMPARE(object->property("success").toBool(), true);
4447 QMetaObject::invokeMethod(object, "writeOtherElements");
4448 QCOMPARE(object->property("success").toBool(), true);
4450 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4451 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4457 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4458 QDeclarativeComponent component(&engine, qmlFile);
4459 QObject *object = component.create();
4460 QVERIFY(object != 0);
4461 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4464 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4465 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4466 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4468 QMetaObject::invokeMethod(object, "performTest");
4470 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4471 QCOMPARE(seq->pointListProperty(), pointList);
4477 void tst_qdeclarativeecmascript::sequenceConversionArray()
4479 // ensure that in JS the returned sequences act just like normal JS Arrays.
4480 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4481 QDeclarativeComponent component(&engine, qmlFile);
4482 QObject *object = component.create();
4483 QVERIFY(object != 0);
4484 QMetaObject::invokeMethod(object, "indexedAccess");
4485 QVERIFY(object->property("success").toBool());
4486 QMetaObject::invokeMethod(object, "arrayOperations");
4487 QVERIFY(object->property("success").toBool());
4488 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4489 QVERIFY(object->property("success").toBool());
4490 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4491 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4495 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4497 // ensure that sequence conversion operations work correctly in a worker thread
4498 // and that serialisation between the main and worker thread succeeds.
4499 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4500 QDeclarativeComponent component(&engine, qmlFile);
4501 QObject *object = component.create();
4502 QVERIFY(object != 0);
4504 QMetaObject::invokeMethod(object, "testIntSequence");
4505 QTRY_VERIFY(object->property("finished").toBool());
4506 QVERIFY(object->property("success").toBool());
4508 QMetaObject::invokeMethod(object, "testQrealSequence");
4509 QTRY_VERIFY(object->property("finished").toBool());
4510 QVERIFY(object->property("success").toBool());
4512 QMetaObject::invokeMethod(object, "testBoolSequence");
4513 QTRY_VERIFY(object->property("finished").toBool());
4514 QVERIFY(object->property("success").toBool());
4516 QMetaObject::invokeMethod(object, "testStringSequence");
4517 QTRY_VERIFY(object->property("finished").toBool());
4518 QVERIFY(object->property("success").toBool());
4520 QMetaObject::invokeMethod(object, "testQStringSequence");
4521 QTRY_VERIFY(object->property("finished").toBool());
4522 QVERIFY(object->property("success").toBool());
4524 QMetaObject::invokeMethod(object, "testUrlSequence");
4525 QTRY_VERIFY(object->property("finished").toBool());
4526 QVERIFY(object->property("success").toBool());
4528 QMetaObject::invokeMethod(object, "testVariantSequence");
4529 QTRY_VERIFY(object->property("finished").toBool());
4530 QVERIFY(object->property("success").toBool());
4535 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4538 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4539 QDeclarativeComponent component(&engine, qmlFile);
4540 QObject *object = component.create();
4541 QVERIFY(object != 0);
4542 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4543 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4544 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4545 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4546 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4551 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4552 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4553 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4554 QDeclarativeComponent component(&engine, qmlFile);
4555 QObject *object = component.create();
4556 QVERIFY(object != 0);
4561 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4563 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4564 QDeclarativeComponent component(&engine, qmlFile);
4565 QObject *object = component.create();
4566 QVERIFY(object != 0);
4567 QMetaObject::invokeMethod(object, "testCopySequences");
4568 QCOMPARE(object->property("success").toBool(), true);
4569 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4570 QCOMPARE(object->property("success").toBool(), true);
4571 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4572 QCOMPARE(object->property("success").toBool(), true);
4576 void tst_qdeclarativeecmascript::assignSequenceTypes()
4578 // test binding array to sequence type property
4580 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.1.qml"));
4581 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4582 QVERIFY(object != 0);
4583 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4584 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4585 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4586 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4587 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4588 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4592 // test binding literal to sequence type property
4594 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.2.qml"));
4595 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4596 QVERIFY(object != 0);
4597 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4598 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4599 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4600 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4601 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4602 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4606 // test binding single value to sequence type property
4608 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.3.qml"));
4609 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4610 QVERIFY(object != 0);
4611 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4612 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4613 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4614 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4618 // test assigning array to sequence type property in js function
4620 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.4.qml"));
4621 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4622 QVERIFY(object != 0);
4623 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4624 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4625 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4626 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4627 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4628 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4632 // test assigning literal to sequence type property in js function
4634 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.5.qml"));
4635 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4636 QVERIFY(object != 0);
4637 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4638 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4639 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4640 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4641 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4642 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4646 // test assigning single value to sequence type property in js function
4648 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.6.qml"));
4649 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4650 QVERIFY(object != 0);
4651 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4652 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4653 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4654 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4659 // Test that assigning a null object works
4660 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4661 void tst_qdeclarativeecmascript::nullObjectBinding()
4663 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4665 QObject *object = component.create();
4666 QVERIFY(object != 0);
4668 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4673 // Test that bindings don't evaluate once the engine has been destroyed
4674 void tst_qdeclarativeecmascript::deletedEngine()
4676 QDeclarativeEngine *engine = new QDeclarativeEngine;
4677 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4679 QObject *object = component.create();
4680 QVERIFY(object != 0);
4682 QCOMPARE(object->property("a").toInt(), 39);
4683 object->setProperty("b", QVariant(9));
4684 QCOMPARE(object->property("a").toInt(), 117);
4688 QCOMPARE(object->property("a").toInt(), 117);
4689 object->setProperty("b", QVariant(10));
4690 QCOMPARE(object->property("a").toInt(), 117);
4695 // Test the crashing part of QTBUG-9705
4696 void tst_qdeclarativeecmascript::libraryScriptAssert()
4698 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4700 QObject *object = component.create();
4701 QVERIFY(object != 0);
4706 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4708 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4710 QObject *object = component.create();
4711 QVERIFY(object != 0);
4713 QCOMPARE(object->property("test1").toInt(), 10);
4714 QCOMPARE(object->property("test2").toInt(), 11);
4716 object->setProperty("runTest", true);
4718 QCOMPARE(object->property("test1"), QVariant());
4719 QCOMPARE(object->property("test2"), QVariant());
4725 void tst_qdeclarativeecmascript::qtbug_9792()
4727 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4729 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4731 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4732 QVERIFY(object != 0);
4734 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4735 object->basicSignal();
4739 transientErrorsMsgCount = 0;
4740 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4742 object->basicSignal();
4744 qInstallMsgHandler(old);
4746 QCOMPARE(transientErrorsMsgCount, 0);
4751 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4752 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4754 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4756 QObject *o = component.create();
4759 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4760 QVERIFY(nested != 0);
4762 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4765 nested = qvariant_cast<QObject *>(o->property("object"));
4766 QVERIFY(nested == 0);
4768 // If the bug is present, the next line will crash
4772 // Test that we shut down without stupid warnings
4773 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4776 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4778 QObject *o = component.create();
4780 transientErrorsMsgCount = 0;
4781 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4785 qInstallMsgHandler(old);
4787 QCOMPARE(transientErrorsMsgCount, 0);
4792 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4794 QObject *o = component.create();
4796 transientErrorsMsgCount = 0;
4797 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4801 qInstallMsgHandler(old);
4803 QCOMPARE(transientErrorsMsgCount, 0);
4807 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4810 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4812 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4815 QVERIFY(o->objectProperty() != 0);
4817 o->setProperty("runTest", true);
4819 QVERIFY(o->objectProperty() == 0);
4825 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4827 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4830 QVERIFY(o->objectProperty() == 0);
4836 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4838 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4840 QString url = component.url().toString();
4841 QString warning = url + ":4: Unable to assign a function to a property.";
4842 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4844 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4847 QVERIFY(!o->property("a").isValid());
4852 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4854 QFETCH(QString, triggerProperty);
4856 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4857 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4859 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4861 QVERIFY(!o->property("a").isValid());
4863 o->setProperty("aNumber", QVariant(5));
4864 o->setProperty(triggerProperty.toUtf8().constData(), true);
4865 QCOMPARE(o->property("a"), QVariant(50));
4867 o->setProperty("aNumber", QVariant(10));
4868 QCOMPARE(o->property("a"), QVariant(100));
4873 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4875 QTest::addColumn<QString>("triggerProperty");
4877 QTest::newRow("assign to property") << "assignToProperty";
4878 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4880 QTest::newRow("assign to value type") << "assignToValueType";
4882 QTest::newRow("use 'this'") << "assignWithThis";
4883 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4886 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4888 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4889 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4891 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4893 QVERIFY(!o->property("a").isValid());
4895 o->setProperty("assignFuncWithoutReturn", true);
4896 QVERIFY(!o->property("a").isValid());
4898 QString url = component.url().toString();
4899 QString warning = url + ":67: Unable to assign QString to int";
4900 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4901 o->setProperty("assignWrongType", true);
4903 warning = url + ":71: Unable to assign QString to int";
4904 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4905 o->setProperty("assignWrongTypeToValueType", true);
4910 void tst_qdeclarativeecmascript::eval()
4912 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4914 QObject *o = component.create();
4917 QCOMPARE(o->property("test1").toBool(), true);
4918 QCOMPARE(o->property("test2").toBool(), true);
4919 QCOMPARE(o->property("test3").toBool(), true);
4920 QCOMPARE(o->property("test4").toBool(), true);
4921 QCOMPARE(o->property("test5").toBool(), true);
4926 void tst_qdeclarativeecmascript::function()
4928 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4930 QObject *o = component.create();
4933 QCOMPARE(o->property("test1").toBool(), true);
4934 QCOMPARE(o->property("test2").toBool(), true);
4935 QCOMPARE(o->property("test3").toBool(), true);
4940 // Test the "Qt.include" method
4941 void tst_qdeclarativeecmascript::include()
4943 // Non-library relative include
4945 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4946 QObject *o = component.create();
4949 QCOMPARE(o->property("test0").toInt(), 99);
4950 QCOMPARE(o->property("test1").toBool(), true);
4951 QCOMPARE(o->property("test2").toBool(), true);
4952 QCOMPARE(o->property("test2_1").toBool(), true);
4953 QCOMPARE(o->property("test3").toBool(), true);
4954 QCOMPARE(o->property("test3_1").toBool(), true);
4959 // Library relative include
4961 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4962 QObject *o = component.create();
4965 QCOMPARE(o->property("test0").toInt(), 99);
4966 QCOMPARE(o->property("test1").toBool(), true);
4967 QCOMPARE(o->property("test2").toBool(), true);
4968 QCOMPARE(o->property("test2_1").toBool(), true);
4969 QCOMPARE(o->property("test3").toBool(), true);
4970 QCOMPARE(o->property("test3_1").toBool(), true);
4977 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4978 QObject *o = component.create();
4981 QCOMPARE(o->property("test1").toBool(), true);
4982 QCOMPARE(o->property("test2").toBool(), true);
4983 QCOMPARE(o->property("test3").toBool(), true);
4984 QCOMPARE(o->property("test4").toBool(), true);
4985 QCOMPARE(o->property("test5").toBool(), true);
4986 QCOMPARE(o->property("test6").toBool(), true);
4991 // Including file with ".pragma library"
4993 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4994 QObject *o = component.create();
4996 QCOMPARE(o->property("test1").toInt(), 100);
5003 TestHTTPServer server(8111);
5004 QVERIFY(server.isValid());
5005 server.serveDirectory(TESTDATA(""));
5007 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
5008 QObject *o = component.create();
5011 QTRY_VERIFY(o->property("done").toBool() == true);
5012 QTRY_VERIFY(o->property("done2").toBool() == true);
5014 QCOMPARE(o->property("test1").toBool(), true);
5015 QCOMPARE(o->property("test2").toBool(), true);
5016 QCOMPARE(o->property("test3").toBool(), true);
5017 QCOMPARE(o->property("test4").toBool(), true);
5018 QCOMPARE(o->property("test5").toBool(), true);
5020 QCOMPARE(o->property("test6").toBool(), true);
5021 QCOMPARE(o->property("test7").toBool(), true);
5022 QCOMPARE(o->property("test8").toBool(), true);
5023 QCOMPARE(o->property("test9").toBool(), true);
5024 QCOMPARE(o->property("test10").toBool(), true);
5031 TestHTTPServer server(8111);
5032 QVERIFY(server.isValid());
5033 server.serveDirectory(TESTDATA(""));
5035 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
5036 QObject *o = component.create();
5039 QTRY_VERIFY(o->property("done").toBool() == true);
5041 QCOMPARE(o->property("test1").toBool(), true);
5042 QCOMPARE(o->property("test2").toBool(), true);
5043 QCOMPARE(o->property("test3").toBool(), true);
5049 void tst_qdeclarativeecmascript::signalHandlers()
5051 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
5052 QObject *o = component.create();
5055 QVERIFY(o->property("count").toInt() == 0);
5056 QMetaObject::invokeMethod(o, "testSignalCall");
5057 QCOMPARE(o->property("count").toInt(), 1);
5059 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5060 QCOMPARE(o->property("count").toInt(), 1);
5061 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5063 QVERIFY(o->property("funcCount").toInt() == 0);
5064 QMetaObject::invokeMethod(o, "testSignalConnection");
5065 QCOMPARE(o->property("funcCount").toInt(), 1);
5067 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5068 QCOMPARE(o->property("funcCount").toInt(), 2);
5070 QMetaObject::invokeMethod(o, "testSignalDefined");
5071 QCOMPARE(o->property("definedResult").toBool(), true);
5073 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5074 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5079 void tst_qdeclarativeecmascript::qtbug_10696()
5081 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
5082 QObject *o = component.create();
5087 void tst_qdeclarativeecmascript::qtbug_11606()
5089 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
5090 QObject *o = component.create();
5092 QCOMPARE(o->property("test").toBool(), true);
5096 void tst_qdeclarativeecmascript::qtbug_11600()
5098 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
5099 QObject *o = component.create();
5101 QCOMPARE(o->property("test").toBool(), true);
5105 void tst_qdeclarativeecmascript::qtbug_21864()
5107 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21864.qml"));
5108 QObject *o = component.create();
5110 QCOMPARE(o->property("test").toBool(), true);
5114 // Reading and writing non-scriptable properties should fail
5115 void tst_qdeclarativeecmascript::nonscriptable()
5117 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
5118 QObject *o = component.create();
5120 QCOMPARE(o->property("readOk").toBool(), true);
5121 QCOMPARE(o->property("writeOk").toBool(), true);
5125 // deleteLater() should not be callable from QML
5126 void tst_qdeclarativeecmascript::deleteLater()
5128 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
5129 QObject *o = component.create();
5131 QCOMPARE(o->property("test").toBool(), true);
5135 void tst_qdeclarativeecmascript::in()
5137 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
5138 QObject *o = component.create();
5140 QCOMPARE(o->property("test1").toBool(), true);
5141 QCOMPARE(o->property("test2").toBool(), true);
5145 void tst_qdeclarativeecmascript::typeOf()
5147 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
5149 // These warnings should not happen once QTBUG-21864 is fixed
5150 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5151 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5153 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5154 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5156 QObject *o = component.create();
5159 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5160 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5161 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5162 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5163 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5164 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5165 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5166 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5167 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5168 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5173 void tst_qdeclarativeecmascript::sharedAttachedObject()
5175 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
5176 QObject *o = component.create();
5178 QCOMPARE(o->property("test1").toBool(), true);
5179 QCOMPARE(o->property("test2").toBool(), true);
5184 void tst_qdeclarativeecmascript::objectName()
5186 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
5187 QObject *o = component.create();
5190 QCOMPARE(o->property("test1").toString(), QString("hello"));
5191 QCOMPARE(o->property("test2").toString(), QString("ell"));
5193 o->setObjectName("world");
5195 QCOMPARE(o->property("test1").toString(), QString("world"));
5196 QCOMPARE(o->property("test2").toString(), QString("orl"));
5201 void tst_qdeclarativeecmascript::writeRemovesBinding()
5203 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
5204 QObject *o = component.create();
5207 QCOMPARE(o->property("test").toBool(), true);
5212 // Test bindings assigned to alias properties actually assign to the alias' target
5213 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5215 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
5216 QObject *o = component.create();
5219 QCOMPARE(o->property("test").toBool(), true);
5224 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5225 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5228 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
5229 QObject *o = component.create();
5232 QCOMPARE(o->property("test").toBool(), true);
5238 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
5239 QObject *o = component.create();
5242 QCOMPARE(o->property("test").toBool(), true);
5248 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
5249 QObject *o = component.create();
5252 QCOMPARE(o->property("test").toBool(), true);
5258 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5259 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5262 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
5263 QObject *o = component.create();
5266 QCOMPARE(o->property("test").toBool(), true);
5272 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
5273 QObject *o = component.create();
5276 QCOMPARE(o->property("test").toBool(), true);
5282 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
5283 QObject *o = component.create();
5286 QCOMPARE(o->property("test").toBool(), true);
5292 // Allow an alais to a composite element
5294 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5296 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
5298 QObject *object = component.create();
5299 QVERIFY(object != 0);
5304 void tst_qdeclarativeecmascript::qtbug_20344()
5306 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
5308 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5309 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5311 QObject *object = component.create();
5312 QVERIFY(object != 0);
5317 void tst_qdeclarativeecmascript::revisionErrors()
5320 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
5321 QString url = component.url().toString();
5323 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5324 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5325 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5327 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5328 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5329 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5330 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5331 QVERIFY(object != 0);
5335 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
5336 QString url = component.url().toString();
5338 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5339 // method2, prop2 from MyRevisionedClass not available
5340 // method4, prop4 from MyRevisionedSubclass not available
5341 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5342 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5343 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5344 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5345 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5347 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5348 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5349 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5350 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5351 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5352 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5353 QVERIFY(object != 0);
5357 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5358 QString url = component.url().toString();
5360 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5361 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5362 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5363 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5364 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5365 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5366 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5367 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5368 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5369 QVERIFY(object != 0);
5374 void tst_qdeclarativeecmascript::revision()
5377 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5378 QString url = component.url().toString();
5380 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5381 QVERIFY(object != 0);
5385 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5386 QString url = component.url().toString();
5388 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5389 QVERIFY(object != 0);
5393 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5394 QString url = component.url().toString();
5396 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5397 QVERIFY(object != 0);
5400 // Test that non-root classes can resolve revisioned methods
5402 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5404 QObject *object = component.create();
5405 QVERIFY(object != 0);
5406 QCOMPARE(object->property("test").toReal(), 11.);
5411 void tst_qdeclarativeecmascript::realToInt()
5413 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5414 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5415 QVERIFY(object != 0);
5417 QMetaObject::invokeMethod(object, "test1");
5418 QCOMPARE(object->value(), int(4));
5419 QMetaObject::invokeMethod(object, "test2");
5420 QCOMPARE(object->value(), int(8));
5422 void tst_qdeclarativeecmascript::dynamicString()
5424 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5425 QObject *object = component.create();
5426 QVERIFY(object != 0);
5427 QCOMPARE(object->property("stringProperty").toString(),
5428 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5431 void tst_qdeclarativeecmascript::automaticSemicolon()
5433 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5434 QObject *object = component.create();
5435 QVERIFY(object != 0);
5438 void tst_qdeclarativeecmascript::unaryExpression()
5440 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5441 QObject *object = component.create();
5442 QVERIFY(object != 0);
5445 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5446 void tst_qdeclarativeecmascript::doubleEvaluate()
5448 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5449 QObject *object = component.create();
5450 QVERIFY(object != 0);
5451 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5453 QCOMPARE(wc->count(), 1);
5455 wc->setProperty("x", 9);
5457 QCOMPARE(wc->count(), 2);
5462 static QStringList messages;
5463 static void captureMsgHandler(QtMsgType, const char *msg)
5465 messages.append(QLatin1String(msg));
5468 void tst_qdeclarativeecmascript::nonNotifyable()
5470 QV4Compiler::enableV4(false);
5471 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5472 QV4Compiler::enableV4(true);
5474 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5476 QObject *object = component.create();
5477 qInstallMsgHandler(old);
5479 QVERIFY(object != 0);
5481 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5482 component.url().toString() +
5483 QLatin1String(":5 depends on non-NOTIFYable properties:");
5484 QString expected2 = QLatin1String(" ") +
5485 QLatin1String(object->metaObject()->className()) +
5486 QLatin1String("::value");
5488 QCOMPARE(messages.length(), 2);
5489 QCOMPARE(messages.at(0), expected1);
5490 QCOMPARE(messages.at(1), expected2);
5495 void tst_qdeclarativeecmascript::forInLoop()
5497 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5498 QObject *object = component.create();
5499 QVERIFY(object != 0);
5501 QMetaObject::invokeMethod(object, "listProperty");
5503 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5504 QCOMPARE(r.size(), 3);
5505 QCOMPARE(r[0],QLatin1String("0=obj1"));
5506 QCOMPARE(r[1],QLatin1String("1=obj2"));
5507 QCOMPARE(r[2],QLatin1String("2=obj3"));
5509 //TODO: should test for in loop for other objects (such as QObjects) as well.
5514 // An object the binding depends on is deleted while the binding is still running
5515 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5517 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5518 QObject *object = component.create();
5519 QVERIFY(object != 0);
5523 void tst_qdeclarativeecmascript::qtbug_22679()
5526 object.setStringProperty(QLatin1String("Please work correctly"));
5527 engine.rootContext()->setContextProperty("contextProp", &object);
5529 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5530 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5531 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5533 QObject *o = component.create();
5535 QCOMPARE(warningsSpy.count(), 0);
5539 void tst_qdeclarativeecmascript::qtbug_22843_data()
5541 QTest::addColumn<bool>("library");
5543 QTest::newRow("without .pragma library") << false;
5544 QTest::newRow("with .pragma library") << true;
5547 void tst_qdeclarativeecmascript::qtbug_22843()
5549 QFETCH(bool, library);
5551 QString fileName("qtbug_22843");
5553 fileName += QLatin1String(".library");
5554 fileName += QLatin1String(".qml");
5556 QDeclarativeComponent component(&engine, TEST_FILE(fileName));
5557 QString url = component.url().toString();
5558 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5559 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5561 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5562 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5563 for (int x = 0; x < 3; ++x) {
5564 warningsSpy.clear();
5565 // For libraries, only the first import attempt should produce a
5566 // SyntaxError warning; subsequent component creation should not
5567 // attempt to reload the script.
5568 bool expectSyntaxError = !library || (x == 0);
5569 if (expectSyntaxError)
5570 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5571 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5572 QObject *object = component.create();
5573 QVERIFY(object != 0);
5574 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5580 void tst_qdeclarativeecmascript::switchStatement()
5583 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.1.qml"));
5584 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5585 QVERIFY(object != 0);
5587 // `object->value()' is the number of executed statements
5589 object->setStringProperty("A");
5590 QCOMPARE(object->value(), 5);
5592 object->setStringProperty("S");
5593 QCOMPARE(object->value(), 3);
5595 object->setStringProperty("D");
5596 QCOMPARE(object->value(), 3);
5598 object->setStringProperty("F");
5599 QCOMPARE(object->value(), 4);
5601 object->setStringProperty("something else");
5602 QCOMPARE(object->value(), 1);
5606 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.2.qml"));
5607 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5608 QVERIFY(object != 0);
5610 // `object->value()' is the number of executed statements
5612 object->setStringProperty("A");
5613 QCOMPARE(object->value(), 5);
5615 object->setStringProperty("S");
5616 QCOMPARE(object->value(), 3);
5618 object->setStringProperty("D");
5619 QCOMPARE(object->value(), 3);
5621 object->setStringProperty("F");
5622 QCOMPARE(object->value(), 3);
5624 object->setStringProperty("something else");
5625 QCOMPARE(object->value(), 4);
5629 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.3.qml"));
5630 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5631 QVERIFY(object != 0);
5633 // `object->value()' is the number of executed statements
5635 object->setStringProperty("A");
5636 QCOMPARE(object->value(), 5);
5638 object->setStringProperty("S");
5639 QCOMPARE(object->value(), 3);
5641 object->setStringProperty("D");
5642 QCOMPARE(object->value(), 3);
5644 object->setStringProperty("F");
5645 QCOMPARE(object->value(), 3);
5647 object->setStringProperty("something else");
5648 QCOMPARE(object->value(), 6);
5652 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.4.qml"));
5654 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5655 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5657 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5658 QVERIFY(object != 0);
5660 // `object->value()' is the number of executed statements
5662 object->setStringProperty("A");
5663 QCOMPARE(object->value(), 5);
5665 object->setStringProperty("S");
5666 QCOMPARE(object->value(), 3);
5668 object->setStringProperty("D");
5669 QCOMPARE(object->value(), 3);
5671 object->setStringProperty("F");
5672 QCOMPARE(object->value(), 3);
5674 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5676 object->setStringProperty("something else");
5680 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.5.qml"));
5681 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5682 QVERIFY(object != 0);
5684 // `object->value()' is the number of executed statements
5686 object->setStringProperty("A");
5687 QCOMPARE(object->value(), 1);
5689 object->setStringProperty("S");
5690 QCOMPARE(object->value(), 1);
5692 object->setStringProperty("D");
5693 QCOMPARE(object->value(), 1);
5695 object->setStringProperty("F");
5696 QCOMPARE(object->value(), 1);
5698 object->setStringProperty("something else");
5699 QCOMPARE(object->value(), 1);
5703 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.6.qml"));
5704 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5705 QVERIFY(object != 0);
5707 // `object->value()' is the number of executed statements
5709 object->setStringProperty("A");
5710 QCOMPARE(object->value(), 123);
5712 object->setStringProperty("S");
5713 QCOMPARE(object->value(), 123);
5715 object->setStringProperty("D");
5716 QCOMPARE(object->value(), 321);
5718 object->setStringProperty("F");
5719 QCOMPARE(object->value(), 321);
5721 object->setStringProperty("something else");
5722 QCOMPARE(object->value(), 0);
5726 void tst_qdeclarativeecmascript::withStatement()
5729 QDeclarativeComponent component(&engine, TEST_FILE("withStatement.1.qml"));
5730 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5731 QVERIFY(object != 0);
5733 QCOMPARE(object->value(), 123);
5737 void tst_qdeclarativeecmascript::tryStatement()
5740 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.1.qml"));
5741 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5742 QVERIFY(object != 0);
5744 QCOMPARE(object->value(), 123);
5748 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.2.qml"));
5749 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5750 QVERIFY(object != 0);
5752 QCOMPARE(object->value(), 321);
5756 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.3.qml"));
5757 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5758 QVERIFY(object != 0);
5760 QCOMPARE(object->value(), 1);
5764 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.4.qml"));
5765 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5766 QVERIFY(object != 0);
5768 QCOMPARE(object->value(), 1);
5772 QTEST_MAIN(tst_qdeclarativeecmascript)
5774 #include "tst_qdeclarativeecmascript.moc"