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 propertyChangeSlots();
156 void propertyVar_data();
158 void propertyVarCpp();
159 void propertyVarOwnership();
160 void propertyVarImplicitOwnership();
161 void propertyVarReparent();
162 void propertyVarReparentNullContext();
163 void propertyVarCircular();
164 void propertyVarCircular2();
165 void propertyVarInheritance();
166 void propertyVarInheritance2();
167 void elementAssign();
168 void objectPassThroughSignals();
169 void objectConversion();
170 void booleanConversion();
171 void handleReferenceManagement();
173 void readonlyDeclaration();
174 void sequenceConversionRead();
175 void sequenceConversionWrite();
176 void sequenceConversionArray();
177 void sequenceConversionThreads();
178 void sequenceConversionBindings();
179 void sequenceConversionCopy();
180 void assignSequenceTypes();
186 void dynamicCreationCrash();
187 void dynamicCreationOwnership();
189 void nullObjectBinding();
190 void deletedEngine();
191 void libraryScriptAssert();
192 void variantsAssignedUndefined();
194 void qtcreatorbug_1289();
195 void noSpuriousWarningsAtShutdown();
196 void canAssignNullToQObject();
197 void functionAssignment_fromBinding();
198 void functionAssignment_fromJS();
199 void functionAssignment_fromJS_data();
200 void functionAssignmentfromJS_invalid();
206 void nonscriptable();
210 void sharedAttachedObject();
212 void writeRemovesBinding();
213 void aliasBindingsAssignCorrectly();
214 void aliasBindingsOverrideTarget();
215 void aliasWritesOverrideBindings();
216 void aliasToCompositeElement();
218 void dynamicString();
220 void signalHandlers();
221 void doubleEvaluate();
223 void nonNotifyable();
224 void deleteWhileBindingRunning();
225 void callQtInvokables();
226 void invokableObjectArg();
227 void invokableObjectRet();
230 void qtbug_22843_data();
232 void revisionErrors();
235 void automaticSemicolon();
236 void unaryExpression();
237 void switchStatement();
238 void withStatement();
242 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
243 QDeclarativeEngine engine;
246 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
248 void tst_qdeclarativeecmascript::assignBasicTypes()
251 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
252 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
253 QVERIFY(object != 0);
254 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
255 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
256 QCOMPARE(object->stringProperty(), QString("Hello World!"));
257 QCOMPARE(object->uintProperty(), uint(10));
258 QCOMPARE(object->intProperty(), -19);
259 QCOMPARE((float)object->realProperty(), float(23.2));
260 QCOMPARE((float)object->doubleProperty(), float(-19.75));
261 QCOMPARE((float)object->floatProperty(), float(8.5));
262 QCOMPARE(object->colorProperty(), QColor("red"));
263 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
264 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
265 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
266 QCOMPARE(object->pointProperty(), QPoint(99,13));
267 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
268 QCOMPARE(object->sizeProperty(), QSize(99, 13));
269 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
270 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
271 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
272 QCOMPARE(object->boolProperty(), true);
273 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
274 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
275 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
279 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
280 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
281 QVERIFY(object != 0);
282 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
283 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
284 QCOMPARE(object->stringProperty(), QString("Hello World!"));
285 QCOMPARE(object->uintProperty(), uint(10));
286 QCOMPARE(object->intProperty(), -19);
287 QCOMPARE((float)object->realProperty(), float(23.2));
288 QCOMPARE((float)object->doubleProperty(), float(-19.75));
289 QCOMPARE((float)object->floatProperty(), float(8.5));
290 QCOMPARE(object->colorProperty(), QColor("red"));
291 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
292 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
293 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
294 QCOMPARE(object->pointProperty(), QPoint(99,13));
295 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
296 QCOMPARE(object->sizeProperty(), QSize(99, 13));
297 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
298 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
299 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
300 QCOMPARE(object->boolProperty(), true);
301 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
302 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
303 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
308 void tst_qdeclarativeecmascript::idShortcutInvalidates()
311 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
312 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
313 QVERIFY(object != 0);
314 QVERIFY(object->objectProperty() != 0);
315 delete object->objectProperty();
316 QVERIFY(object->objectProperty() == 0);
321 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
322 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
323 QVERIFY(object != 0);
324 QVERIFY(object->objectProperty() != 0);
325 delete object->objectProperty();
326 QVERIFY(object->objectProperty() == 0);
331 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
334 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
335 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
336 QVERIFY(object != 0);
337 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
341 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
342 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
343 QVERIFY(object != 0);
344 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
349 void tst_qdeclarativeecmascript::signalAssignment()
352 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
353 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
354 QVERIFY(object != 0);
355 QCOMPARE(object->string(), QString());
356 emit object->basicSignal();
357 QCOMPARE(object->string(), QString("pass"));
362 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
363 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
364 QVERIFY(object != 0);
365 QCOMPARE(object->string(), QString());
366 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
367 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
372 void tst_qdeclarativeecmascript::methods()
375 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
376 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
377 QVERIFY(object != 0);
378 QCOMPARE(object->methodCalled(), false);
379 QCOMPARE(object->methodIntCalled(), false);
380 emit object->basicSignal();
381 QCOMPARE(object->methodCalled(), true);
382 QCOMPARE(object->methodIntCalled(), false);
387 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
388 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
389 QVERIFY(object != 0);
390 QCOMPARE(object->methodCalled(), false);
391 QCOMPARE(object->methodIntCalled(), false);
392 emit object->basicSignal();
393 QCOMPARE(object->methodCalled(), false);
394 QCOMPARE(object->methodIntCalled(), true);
399 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
400 QObject *object = component.create();
401 QVERIFY(object != 0);
402 QCOMPARE(object->property("test").toInt(), 19);
407 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
408 QObject *object = component.create();
409 QVERIFY(object != 0);
410 QCOMPARE(object->property("test").toInt(), 19);
411 QCOMPARE(object->property("test2").toInt(), 17);
412 QCOMPARE(object->property("test3").toInt(), 16);
417 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
418 QObject *object = component.create();
419 QVERIFY(object != 0);
420 QCOMPARE(object->property("test").toInt(), 9);
425 void tst_qdeclarativeecmascript::bindingLoop()
427 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
428 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
429 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
430 QObject *object = component.create();
431 QVERIFY(object != 0);
435 void tst_qdeclarativeecmascript::basicExpressions_data()
437 QTest::addColumn<QString>("expression");
438 QTest::addColumn<QVariant>("result");
439 QTest::addColumn<bool>("nest");
441 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
442 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
443 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
444 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
445 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
446 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
447 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
448 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
449 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
450 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
451 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
452 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
453 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
454 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
455 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
456 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
457 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
458 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
459 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
462 void tst_qdeclarativeecmascript::basicExpressions()
464 QFETCH(QString, expression);
465 QFETCH(QVariant, result);
471 MyDefaultObject1 default1;
472 MyDefaultObject3 default3;
473 object1.setStringProperty("Object1");
474 object2.setStringProperty("Object2");
475 object3.setStringProperty("Object3");
477 QDeclarativeContext context(engine.rootContext());
478 QDeclarativeContext nestedContext(&context);
480 context.setContextObject(&default1);
481 context.setContextProperty("a", QVariant(1944));
482 context.setContextProperty("b", QVariant("Milk"));
483 context.setContextProperty("object", &object1);
484 context.setContextProperty("objectOverride", &object2);
485 nestedContext.setContextObject(&default3);
486 nestedContext.setContextProperty("b", QVariant("Cow"));
487 nestedContext.setContextProperty("objectOverride", &object3);
488 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
490 MyExpression expr(nest?&nestedContext:&context, expression);
491 QCOMPARE(expr.evaluate(), result);
494 void tst_qdeclarativeecmascript::arrayExpressions()
500 QDeclarativeContext context(engine.rootContext());
501 context.setContextProperty("a", &obj1);
502 context.setContextProperty("b", &obj2);
503 context.setContextProperty("c", &obj3);
505 MyExpression expr(&context, "[a, b, c, 10]");
506 QVariant result = expr.evaluate();
507 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
508 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
509 QCOMPARE(list.count(), 4);
510 QCOMPARE(list.at(0), &obj1);
511 QCOMPARE(list.at(1), &obj2);
512 QCOMPARE(list.at(2), &obj3);
513 QCOMPARE(list.at(3), (QObject *)0);
516 // Tests that modifying a context property will reevaluate expressions
517 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
519 QDeclarativeContext context(engine.rootContext());
522 MyQmlObject *object3 = new MyQmlObject;
524 object1.setStringProperty("Hello");
525 object2.setStringProperty("World");
527 context.setContextProperty("testProp", QVariant(1));
528 context.setContextProperty("testObj", &object1);
529 context.setContextProperty("testObj2", object3);
532 MyExpression expr(&context, "testProp + 1");
533 QCOMPARE(expr.changed, false);
534 QCOMPARE(expr.evaluate(), QVariant(2));
536 context.setContextProperty("testProp", QVariant(2));
537 QCOMPARE(expr.changed, true);
538 QCOMPARE(expr.evaluate(), QVariant(3));
542 MyExpression expr(&context, "testProp + testProp + testProp");
543 QCOMPARE(expr.changed, false);
544 QCOMPARE(expr.evaluate(), QVariant(6));
546 context.setContextProperty("testProp", QVariant(4));
547 QCOMPARE(expr.changed, true);
548 QCOMPARE(expr.evaluate(), QVariant(12));
552 MyExpression expr(&context, "testObj.stringProperty");
553 QCOMPARE(expr.changed, false);
554 QCOMPARE(expr.evaluate(), QVariant("Hello"));
556 context.setContextProperty("testObj", &object2);
557 QCOMPARE(expr.changed, true);
558 QCOMPARE(expr.evaluate(), QVariant("World"));
562 MyExpression expr(&context, "testObj.stringProperty /**/");
563 QCOMPARE(expr.changed, false);
564 QCOMPARE(expr.evaluate(), QVariant("World"));
566 context.setContextProperty("testObj", &object1);
567 QCOMPARE(expr.changed, true);
568 QCOMPARE(expr.evaluate(), QVariant("Hello"));
572 MyExpression expr(&context, "testObj2");
573 QCOMPARE(expr.changed, false);
574 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
580 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
582 QDeclarativeContext context(engine.rootContext());
586 context.setContextProperty("testObj", &object1);
588 object1.setStringProperty(QLatin1String("Hello"));
589 object2.setStringProperty(QLatin1String("Dog"));
590 object3.setStringProperty(QLatin1String("Cat"));
593 MyExpression expr(&context, "testObj.stringProperty");
594 QCOMPARE(expr.changed, false);
595 QCOMPARE(expr.evaluate(), QVariant("Hello"));
597 object1.setStringProperty(QLatin1String("World"));
598 QCOMPARE(expr.changed, true);
599 QCOMPARE(expr.evaluate(), QVariant("World"));
603 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
604 QCOMPARE(expr.changed, false);
605 QCOMPARE(expr.evaluate(), QVariant());
607 object1.setObjectProperty(&object2);
608 QCOMPARE(expr.changed, true);
609 expr.changed = false;
610 QCOMPARE(expr.evaluate(), QVariant("Dog"));
612 object1.setObjectProperty(&object3);
613 QCOMPARE(expr.changed, true);
614 expr.changed = false;
615 QCOMPARE(expr.evaluate(), QVariant("Cat"));
617 object1.setObjectProperty(0);
618 QCOMPARE(expr.changed, true);
619 expr.changed = false;
620 QCOMPARE(expr.evaluate(), QVariant());
622 object1.setObjectProperty(&object3);
623 QCOMPARE(expr.changed, true);
624 expr.changed = false;
625 QCOMPARE(expr.evaluate(), QVariant("Cat"));
627 object3.setStringProperty("Donkey");
628 QCOMPARE(expr.changed, true);
629 expr.changed = false;
630 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
634 void tst_qdeclarativeecmascript::deferredProperties()
636 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
637 MyDeferredObject *object =
638 qobject_cast<MyDeferredObject *>(component.create());
639 QVERIFY(object != 0);
640 QCOMPARE(object->value(), 0);
641 QVERIFY(object->objectProperty() == 0);
642 QVERIFY(object->objectProperty2() != 0);
643 qmlExecuteDeferred(object);
644 QCOMPARE(object->value(), 10);
645 QVERIFY(object->objectProperty() != 0);
646 MyQmlObject *qmlObject =
647 qobject_cast<MyQmlObject *>(object->objectProperty());
648 QVERIFY(qmlObject != 0);
649 QCOMPARE(qmlObject->value(), 10);
650 object->setValue(19);
651 QCOMPARE(qmlObject->value(), 19);
656 // Check errors on deferred properties are correctly emitted
657 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
659 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
660 MyDeferredObject *object =
661 qobject_cast<MyDeferredObject *>(component.create());
662 QVERIFY(object != 0);
663 QCOMPARE(object->value(), 0);
664 QVERIFY(object->objectProperty() == 0);
665 QVERIFY(object->objectProperty2() == 0);
667 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
668 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
670 qmlExecuteDeferred(object);
675 void tst_qdeclarativeecmascript::extensionObjects()
677 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
678 MyExtendedObject *object =
679 qobject_cast<MyExtendedObject *>(component.create());
680 QVERIFY(object != 0);
681 QCOMPARE(object->baseProperty(), 13);
682 QCOMPARE(object->coreProperty(), 9);
683 object->setProperty("extendedProperty", QVariant(11));
684 object->setProperty("baseExtendedProperty", QVariant(92));
685 QCOMPARE(object->coreProperty(), 11);
686 QCOMPARE(object->baseProperty(), 92);
688 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
690 QCOMPARE(nested->baseProperty(), 13);
691 QCOMPARE(nested->coreProperty(), 9);
692 nested->setProperty("extendedProperty", QVariant(11));
693 nested->setProperty("baseExtendedProperty", QVariant(92));
694 QCOMPARE(nested->coreProperty(), 11);
695 QCOMPARE(nested->baseProperty(), 92);
700 void tst_qdeclarativeecmascript::overrideExtensionProperties()
702 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
703 OverrideDefaultPropertyObject *object =
704 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
705 QVERIFY(object != 0);
706 QVERIFY(object->secondProperty() != 0);
707 QVERIFY(object->firstProperty() == 0);
712 void tst_qdeclarativeecmascript::attachedProperties()
715 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
716 QObject *object = component.create();
717 QVERIFY(object != 0);
718 QCOMPARE(object->property("a").toInt(), 19);
719 QCOMPARE(object->property("b").toInt(), 19);
720 QCOMPARE(object->property("c").toInt(), 19);
721 QCOMPARE(object->property("d").toInt(), 19);
726 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
727 QObject *object = component.create();
728 QVERIFY(object != 0);
729 QCOMPARE(object->property("a").toInt(), 26);
730 QCOMPARE(object->property("b").toInt(), 26);
731 QCOMPARE(object->property("c").toInt(), 26);
732 QCOMPARE(object->property("d").toInt(), 26);
738 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
739 QObject *object = component.create();
740 QVERIFY(object != 0);
742 QMetaObject::invokeMethod(object, "writeValue2");
744 MyQmlAttachedObject *attached =
745 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
746 QVERIFY(attached != 0);
748 QCOMPARE(attached->value2(), 9);
753 void tst_qdeclarativeecmascript::enums()
757 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
758 QObject *object = component.create();
759 QVERIFY(object != 0);
761 QCOMPARE(object->property("a").toInt(), 0);
762 QCOMPARE(object->property("b").toInt(), 1);
763 QCOMPARE(object->property("c").toInt(), 2);
764 QCOMPARE(object->property("d").toInt(), 3);
765 QCOMPARE(object->property("e").toInt(), 0);
766 QCOMPARE(object->property("f").toInt(), 1);
767 QCOMPARE(object->property("g").toInt(), 2);
768 QCOMPARE(object->property("h").toInt(), 3);
769 QCOMPARE(object->property("i").toInt(), 19);
770 QCOMPARE(object->property("j").toInt(), 19);
774 // Non-existent enums
776 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
778 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
779 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
780 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
781 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
783 QObject *object = component.create();
784 QVERIFY(object != 0);
785 QCOMPARE(object->property("a").toInt(), 0);
786 QCOMPARE(object->property("b").toInt(), 0);
792 void tst_qdeclarativeecmascript::valueTypeFunctions()
794 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
795 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
797 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
798 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
804 Tests that writing a constant to a property with a binding on it disables the
807 void tst_qdeclarativeecmascript::constantsOverrideBindings()
811 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
812 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
813 QVERIFY(object != 0);
815 QCOMPARE(object->property("c2").toInt(), 0);
816 object->setProperty("c1", QVariant(9));
817 QCOMPARE(object->property("c2").toInt(), 9);
819 emit object->basicSignal();
821 QCOMPARE(object->property("c2").toInt(), 13);
822 object->setProperty("c1", QVariant(8));
823 QCOMPARE(object->property("c2").toInt(), 13);
828 // During construction
830 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
831 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
832 QVERIFY(object != 0);
834 QCOMPARE(object->property("c1").toInt(), 0);
835 QCOMPARE(object->property("c2").toInt(), 10);
836 object->setProperty("c1", QVariant(9));
837 QCOMPARE(object->property("c1").toInt(), 9);
838 QCOMPARE(object->property("c2").toInt(), 10);
846 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
847 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
848 QVERIFY(object != 0);
850 QCOMPARE(object->property("c2").toInt(), 0);
851 object->setProperty("c1", QVariant(9));
852 QCOMPARE(object->property("c2").toInt(), 9);
854 object->setProperty("c2", QVariant(13));
855 QCOMPARE(object->property("c2").toInt(), 13);
856 object->setProperty("c1", QVariant(7));
857 QCOMPARE(object->property("c1").toInt(), 7);
858 QCOMPARE(object->property("c2").toInt(), 13);
866 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
867 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
868 QVERIFY(object != 0);
870 QCOMPARE(object->property("c1").toInt(), 0);
871 QCOMPARE(object->property("c3").toInt(), 10);
872 object->setProperty("c1", QVariant(9));
873 QCOMPARE(object->property("c1").toInt(), 9);
874 QCOMPARE(object->property("c3").toInt(), 10);
881 Tests that assigning a binding to a property that already has a binding causes
882 the original binding to be disabled.
884 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
886 QDeclarativeComponent component(&engine,
887 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
888 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
889 QVERIFY(object != 0);
891 QCOMPARE(object->property("c1").toInt(), 0);
892 QCOMPARE(object->property("c2").toInt(), 0);
893 QCOMPARE(object->property("c3").toInt(), 0);
895 object->setProperty("c1", QVariant(9));
896 QCOMPARE(object->property("c1").toInt(), 9);
897 QCOMPARE(object->property("c2").toInt(), 0);
898 QCOMPARE(object->property("c3").toInt(), 0);
900 object->setProperty("c3", QVariant(8));
901 QCOMPARE(object->property("c1").toInt(), 9);
902 QCOMPARE(object->property("c2").toInt(), 8);
903 QCOMPARE(object->property("c3").toInt(), 8);
909 Access a non-existent attached object.
911 Tests for a regression where this used to crash.
913 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
915 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
917 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
918 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
920 QObject *object = component.create();
921 QVERIFY(object != 0);
926 void tst_qdeclarativeecmascript::scope()
929 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
930 QObject *object = component.create();
931 QVERIFY(object != 0);
933 QCOMPARE(object->property("test1").toInt(), 1);
934 QCOMPARE(object->property("test2").toInt(), 2);
935 QCOMPARE(object->property("test3").toString(), QString("1Test"));
936 QCOMPARE(object->property("test4").toString(), QString("2Test"));
937 QCOMPARE(object->property("test5").toInt(), 1);
938 QCOMPARE(object->property("test6").toInt(), 1);
939 QCOMPARE(object->property("test7").toInt(), 2);
940 QCOMPARE(object->property("test8").toInt(), 2);
941 QCOMPARE(object->property("test9").toInt(), 1);
942 QCOMPARE(object->property("test10").toInt(), 3);
948 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
949 QObject *object = component.create();
950 QVERIFY(object != 0);
952 QCOMPARE(object->property("test1").toInt(), 19);
953 QCOMPARE(object->property("test2").toInt(), 19);
954 QCOMPARE(object->property("test3").toInt(), 14);
955 QCOMPARE(object->property("test4").toInt(), 14);
956 QCOMPARE(object->property("test5").toInt(), 24);
957 QCOMPARE(object->property("test6").toInt(), 24);
963 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
964 QObject *object = component.create();
965 QVERIFY(object != 0);
967 QCOMPARE(object->property("test1").toBool(), true);
968 QCOMPARE(object->property("test2").toBool(), true);
969 QCOMPARE(object->property("test3").toBool(), true);
974 // Signal argument scope
976 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
977 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
978 QVERIFY(object != 0);
980 QCOMPARE(object->property("test").toInt(), 0);
981 QCOMPARE(object->property("test2").toString(), QString());
983 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
985 QCOMPARE(object->property("test").toInt(), 13);
986 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
992 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
993 QObject *object = component.create();
994 QVERIFY(object != 0);
996 QCOMPARE(object->property("test1").toBool(), true);
997 QCOMPARE(object->property("test2").toBool(), true);
1003 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
1004 QObject *object = component.create();
1005 QVERIFY(object != 0);
1007 QCOMPARE(object->property("test").toBool(), true);
1013 // In 4.7, non-library javascript files that had no imports shared the imports of their
1014 // importing context
1015 void tst_qdeclarativeecmascript::importScope()
1017 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1018 QObject *o = component.create();
1021 QCOMPARE(o->property("test").toInt(), 240);
1027 Tests that "any" type passes through a synthesized signal parameter. This
1028 is essentially a test of QDeclarativeMetaType::copy()
1030 void tst_qdeclarativeecmascript::signalParameterTypes()
1032 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1033 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1034 QVERIFY(object != 0);
1036 emit object->basicSignal();
1038 QCOMPARE(object->property("intProperty").toInt(), 10);
1039 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1040 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1041 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1042 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1043 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1049 Test that two JS objects for the same QObject compare as equal.
1051 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1053 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1054 QObject *object = component.create();
1055 QVERIFY(object != 0);
1057 QCOMPARE(object->property("test1").toBool(), true);
1058 QCOMPARE(object->property("test2").toBool(), true);
1059 QCOMPARE(object->property("test3").toBool(), true);
1060 QCOMPARE(object->property("test4").toBool(), true);
1061 QCOMPARE(object->property("test5").toBool(), true);
1067 Confirm bindings and alias properties can coexist.
1069 Tests for a regression where the binding would not reevaluate.
1071 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1073 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1074 QObject *object = component.create();
1075 QVERIFY(object != 0);
1077 QCOMPARE(object->property("c2").toInt(), 3);
1078 QCOMPARE(object->property("c3").toInt(), 3);
1080 object->setProperty("c2", QVariant(19));
1082 QCOMPARE(object->property("c2").toInt(), 19);
1083 QCOMPARE(object->property("c3").toInt(), 19);
1089 Ensure that we can write undefined value to an alias property,
1090 and that the aliased property is reset correctly if possible.
1092 void tst_qdeclarativeecmascript::aliasPropertyReset()
1094 QObject *object = 0;
1096 // test that a manual write (of undefined) to a resettable aliased property succeeds
1097 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1098 object = c1.create();
1099 QVERIFY(object != 0);
1100 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1101 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1102 QMetaObject::invokeMethod(object, "resetAliased");
1103 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1104 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1107 // test that a manual write (of undefined) to a resettable alias property succeeds
1108 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1109 object = c2.create();
1110 QVERIFY(object != 0);
1111 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1112 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1113 QMetaObject::invokeMethod(object, "resetAlias");
1114 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1115 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1118 // test that an alias to a bound property works correctly
1119 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1120 object = c3.create();
1121 QVERIFY(object != 0);
1122 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1123 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1124 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1125 QMetaObject::invokeMethod(object, "resetAlias");
1126 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1127 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1128 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1131 // test that a manual write (of undefined) to a resettable alias property
1132 // whose aliased property's object has been deleted, does not crash.
1133 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1134 object = c4.create();
1135 QVERIFY(object != 0);
1136 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1137 QObject *loader = object->findChild<QObject*>("loader");
1138 QVERIFY(loader != 0);
1140 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1141 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1142 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1143 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1144 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1147 // test that binding an alias property to an undefined value works correctly
1148 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1149 object = c5.create();
1150 QVERIFY(object != 0);
1151 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1154 // test that a manual write (of undefined) to a non-resettable property fails properly
1155 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1156 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1157 QDeclarativeComponent e1(&engine, url);
1158 object = e1.create();
1159 QVERIFY(object != 0);
1160 QCOMPARE(object->property("intAlias").value<int>(), 12);
1161 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1162 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1163 QMetaObject::invokeMethod(object, "resetAlias");
1164 QCOMPARE(object->property("intAlias").value<int>(), 12);
1165 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1169 void tst_qdeclarativeecmascript::dynamicCreation_data()
1171 QTest::addColumn<QString>("method");
1172 QTest::addColumn<QString>("createdName");
1174 QTest::newRow("One") << "createOne" << "objectOne";
1175 QTest::newRow("Two") << "createTwo" << "objectTwo";
1176 QTest::newRow("Three") << "createThree" << "objectThree";
1180 Test using createQmlObject to dynamically generate an item
1181 Also using createComponent is tested.
1183 void tst_qdeclarativeecmascript::dynamicCreation()
1185 QFETCH(QString, method);
1186 QFETCH(QString, createdName);
1188 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1189 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1190 QVERIFY(object != 0);
1192 QMetaObject::invokeMethod(object, method.toUtf8());
1193 QObject *created = object->objectProperty();
1195 QCOMPARE(created->objectName(), createdName);
1201 Tests the destroy function
1203 void tst_qdeclarativeecmascript::dynamicDestruction()
1206 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1207 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1208 QVERIFY(object != 0);
1209 QDeclarativeGuard<QObject> createdQmlObject = 0;
1211 QMetaObject::invokeMethod(object, "create");
1212 createdQmlObject = object->objectProperty();
1213 QVERIFY(createdQmlObject);
1214 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1216 QMetaObject::invokeMethod(object, "killOther");
1217 QVERIFY(createdQmlObject);
1218 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1219 QVERIFY(createdQmlObject);
1220 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1221 if (createdQmlObject) {
1223 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1226 QVERIFY(!createdQmlObject);
1228 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1229 QMetaObject::invokeMethod(object, "killMe");
1232 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1237 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1238 QObject *o = component.create();
1241 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1243 QMetaObject::invokeMethod(o, "create");
1245 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1247 QMetaObject::invokeMethod(o, "destroy");
1249 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1251 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1258 tests that id.toString() works
1260 void tst_qdeclarativeecmascript::objectToString()
1262 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1263 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1264 QVERIFY(object != 0);
1265 QMetaObject::invokeMethod(object, "testToString");
1266 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1267 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1273 tests that id.hasOwnProperty() works
1275 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1277 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1278 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1279 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1280 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1282 QDeclarativeComponent component(&engine, url);
1283 QObject *object = component.create();
1284 QVERIFY(object != 0);
1286 // test QObjects in QML
1287 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1288 QVERIFY(object->property("result").value<bool>() == true);
1289 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1290 QVERIFY(object->property("result").value<bool>() == false);
1292 // now test other types in QML
1293 QObject *child = object->findChild<QObject*>("typeObj");
1294 QVERIFY(child != 0);
1295 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1296 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1297 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1298 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1299 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1300 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1301 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1302 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1303 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1304 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1305 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1306 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1308 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1309 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1310 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1311 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1312 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1313 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1314 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1315 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1316 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1322 Tests bindings that indirectly cause their own deletion work.
1324 This test is best run under valgrind to ensure no invalid memory access occur.
1326 void tst_qdeclarativeecmascript::selfDeletingBinding()
1329 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1330 QObject *object = component.create();
1331 QVERIFY(object != 0);
1332 object->setProperty("triggerDelete", true);
1337 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1338 QObject *object = component.create();
1339 QVERIFY(object != 0);
1340 object->setProperty("triggerDelete", true);
1346 Test that extended object properties can be accessed.
1348 This test a regression where this used to crash. The issue was specificially
1349 for extended objects that did not include a synthesized meta object (so non-root
1350 and no synthesiszed properties).
1352 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1354 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1355 QObject *object = component.create();
1356 QVERIFY(object != 0);
1361 Test file/lineNumbers for binding/Script errors.
1363 void tst_qdeclarativeecmascript::scriptErrors()
1365 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1366 QString url = component.url().toString();
1368 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1369 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1370 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1371 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1372 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1373 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1374 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1375 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1377 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1378 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1379 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1380 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1381 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1382 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1383 QVERIFY(object != 0);
1385 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1386 emit object->basicSignal();
1388 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1389 emit object->anotherBasicSignal();
1391 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1392 emit object->thirdBasicSignal();
1398 Test file/lineNumbers for inline functions.
1400 void tst_qdeclarativeecmascript::functionErrors()
1402 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1403 QString url = component.url().toString();
1405 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1407 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1409 QObject *object = component.create();
1410 QVERIFY(object != 0);
1413 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1414 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1415 url = componentTwo.url().toString();
1416 object = componentTwo.create();
1417 QVERIFY(object != 0);
1419 QString srpname = object->property("srp_name").toString();
1421 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1422 QLatin1String(" is not a function");
1423 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1424 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1429 Test various errors that can occur when assigning a property from script
1431 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1433 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1435 QString url = component.url().toString();
1437 QObject *object = component.create();
1438 QVERIFY(object != 0);
1440 QCOMPARE(object->property("test1").toBool(), true);
1441 QCOMPARE(object->property("test2").toBool(), true);
1447 Test bindings still work when the reeval is triggered from within
1450 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1452 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1453 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1454 QVERIFY(object != 0);
1456 QCOMPARE(object->property("base").toReal(), 50.);
1457 QCOMPARE(object->property("test1").toReal(), 50.);
1458 QCOMPARE(object->property("test2").toReal(), 50.);
1460 object->basicSignal();
1462 QCOMPARE(object->property("base").toReal(), 200.);
1463 QCOMPARE(object->property("test1").toReal(), 200.);
1464 QCOMPARE(object->property("test2").toReal(), 200.);
1466 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1468 QCOMPARE(object->property("base").toReal(), 400.);
1469 QCOMPARE(object->property("test1").toReal(), 400.);
1470 QCOMPARE(object->property("test2").toReal(), 400.);
1476 Test that list properties can be iterated from ECMAScript
1478 void tst_qdeclarativeecmascript::listProperties()
1480 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1481 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1482 QVERIFY(object != 0);
1484 QCOMPARE(object->property("test1").toInt(), 21);
1485 QCOMPARE(object->property("test2").toInt(), 2);
1486 QCOMPARE(object->property("test3").toBool(), true);
1487 QCOMPARE(object->property("test4").toBool(), true);
1492 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1494 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1495 QString url = component.url().toString();
1497 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1499 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1500 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1501 QVERIFY(object != 0);
1503 QCOMPARE(object->property("test").toBool(), false);
1505 MyQmlObject object2;
1506 MyQmlObject object3;
1507 object2.setObjectProperty(&object3);
1508 object->setObjectProperty(&object2);
1510 QCOMPARE(object->property("test").toBool(), true);
1515 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1517 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1518 QString url = component.url().toString();
1520 QString warning = component.url().toString() + ":6: Error: JS exception";
1522 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1523 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1524 QVERIFY(object != 0);
1528 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1530 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1531 QString url = component.url().toString();
1533 QString warning = component.url().toString() + ":5: Error: JS exception";
1535 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1536 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1537 QVERIFY(object != 0);
1541 static int transientErrorsMsgCount = 0;
1542 static void transientErrorsMsgHandler(QtMsgType, const char *)
1544 ++transientErrorsMsgCount;
1547 // Check that transient binding errors are not displayed
1548 void tst_qdeclarativeecmascript::transientErrors()
1551 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1553 transientErrorsMsgCount = 0;
1554 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1556 QObject *object = component.create();
1557 QVERIFY(object != 0);
1559 qInstallMsgHandler(old);
1561 QCOMPARE(transientErrorsMsgCount, 0);
1566 // One binding erroring multiple times, but then resolving
1568 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1570 transientErrorsMsgCount = 0;
1571 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1573 QObject *object = component.create();
1574 QVERIFY(object != 0);
1576 qInstallMsgHandler(old);
1578 QCOMPARE(transientErrorsMsgCount, 0);
1584 // Check that errors during shutdown are minimized
1585 void tst_qdeclarativeecmascript::shutdownErrors()
1587 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1588 QObject *object = component.create();
1589 QVERIFY(object != 0);
1591 transientErrorsMsgCount = 0;
1592 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1596 qInstallMsgHandler(old);
1597 QCOMPARE(transientErrorsMsgCount, 0);
1600 void tst_qdeclarativeecmascript::compositePropertyType()
1602 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1604 QTest::ignoreMessage(QtDebugMsg, "hello world");
1605 QObject *object = qobject_cast<QObject *>(component.create());
1610 void tst_qdeclarativeecmascript::jsObject()
1612 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1613 QObject *object = component.create();
1614 QVERIFY(object != 0);
1616 QCOMPARE(object->property("test").toInt(), 92);
1621 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1624 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1625 QObject *object = component.create();
1626 QVERIFY(object != 0);
1628 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1630 object->setProperty("setUndefined", true);
1632 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1634 object->setProperty("setUndefined", false);
1636 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1641 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1642 QObject *object = component.create();
1643 QVERIFY(object != 0);
1645 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1647 QMetaObject::invokeMethod(object, "doReset");
1649 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1655 // Aliases to variant properties should work
1656 void tst_qdeclarativeecmascript::qtbug_22464()
1658 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1659 QObject *object = component.create();
1660 QVERIFY(object != 0);
1662 QCOMPARE(object->property("test").toBool(), true);
1667 void tst_qdeclarativeecmascript::qtbug_21580()
1669 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
1671 QObject *object = component.create();
1672 QVERIFY(object != 0);
1674 QCOMPARE(object->property("test").toBool(), true);
1680 void tst_qdeclarativeecmascript::bug1()
1682 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1683 QObject *object = component.create();
1684 QVERIFY(object != 0);
1686 QCOMPARE(object->property("test").toInt(), 14);
1688 object->setProperty("a", 11);
1690 QCOMPARE(object->property("test").toInt(), 3);
1692 object->setProperty("b", true);
1694 QCOMPARE(object->property("test").toInt(), 9);
1699 void tst_qdeclarativeecmascript::bug2()
1701 QDeclarativeComponent component(&engine);
1702 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1704 QObject *object = component.create();
1705 QVERIFY(object != 0);
1710 // Don't crash in createObject when the component has errors.
1711 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1713 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1714 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1715 QVERIFY(object != 0);
1717 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1718 QMetaObject::invokeMethod(object, "dontCrash");
1719 QObject *created = object->objectProperty();
1720 QVERIFY(created == 0);
1725 // ownership transferred to JS, ensure that GC runs the dtor
1726 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1729 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1731 // allow the engine to go out of scope too.
1733 QDeclarativeEngine dcoEngine;
1734 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1735 QObject *object = component.create();
1736 QVERIFY(object != 0);
1737 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1738 QVERIFY(mdcdo != 0);
1739 mdcdo->setDtorCount(&dtorCount);
1741 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1742 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1744 // we do this once manually, but it should be done automatically
1745 // when the engine goes out of scope (since it should gc in dtor)
1746 QMetaObject::invokeMethod(object, "performGc");
1749 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1755 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1756 QCOMPARE(dtorCount, expectedDtorCount);
1760 void tst_qdeclarativeecmascript::regExpBug()
1762 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1763 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1764 QVERIFY(object != 0);
1765 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1769 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1771 QString functionSource = QLatin1String("(function(object) { return ") +
1772 QLatin1String(source) + QLatin1String(" })");
1774 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1777 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1778 if (function.IsEmpty())
1780 v8::Handle<v8::Value> args[] = { o };
1781 function->Call(engine->global(), 1, args);
1782 return tc.HasCaught();
1785 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1786 const char *source, v8::Handle<v8::Value> result)
1788 QString functionSource = QLatin1String("(function(object) { return ") +
1789 QLatin1String(source) + QLatin1String(" })");
1791 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1794 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1795 if (function.IsEmpty())
1797 v8::Handle<v8::Value> args[] = { o };
1799 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1804 return value->StrictEquals(result);
1807 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1810 QString functionSource = QLatin1String("(function(object) { return ") +
1811 QLatin1String(source) + QLatin1String(" })");
1813 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1815 return v8::Handle<v8::Value>();
1816 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1817 if (function.IsEmpty())
1818 return v8::Handle<v8::Value>();
1819 v8::Handle<v8::Value> args[] = { o };
1821 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1824 return v8::Handle<v8::Value>();
1828 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1829 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1830 #define EVALUATE(source) evaluate(engine, object, source)
1832 void tst_qdeclarativeecmascript::callQtInvokables()
1834 MyInvokableObject o;
1836 QDeclarativeEngine qmlengine;
1837 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1839 QV8Engine *engine = ep->v8engine();
1841 v8::HandleScope handle_scope;
1842 v8::Context::Scope scope(engine->context());
1844 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1846 // Non-existent methods
1848 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1849 QCOMPARE(o.error(), false);
1850 QCOMPARE(o.invoked(), -1);
1851 QCOMPARE(o.actuals().count(), 0);
1854 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1855 QCOMPARE(o.error(), false);
1856 QCOMPARE(o.invoked(), -1);
1857 QCOMPARE(o.actuals().count(), 0);
1859 // Insufficient arguments
1861 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1862 QCOMPARE(o.error(), false);
1863 QCOMPARE(o.invoked(), -1);
1864 QCOMPARE(o.actuals().count(), 0);
1867 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1868 QCOMPARE(o.error(), false);
1869 QCOMPARE(o.invoked(), -1);
1870 QCOMPARE(o.actuals().count(), 0);
1872 // Excessive arguments
1874 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1875 QCOMPARE(o.error(), false);
1876 QCOMPARE(o.invoked(), 8);
1877 QCOMPARE(o.actuals().count(), 1);
1878 QCOMPARE(o.actuals().at(0), QVariant(10));
1881 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1882 QCOMPARE(o.error(), false);
1883 QCOMPARE(o.invoked(), 9);
1884 QCOMPARE(o.actuals().count(), 2);
1885 QCOMPARE(o.actuals().at(0), QVariant(10));
1886 QCOMPARE(o.actuals().at(1), QVariant(11));
1888 // Test return types
1890 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1891 QCOMPARE(o.error(), false);
1892 QCOMPARE(o.invoked(), 0);
1893 QCOMPARE(o.actuals().count(), 0);
1896 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1897 QCOMPARE(o.error(), false);
1898 QCOMPARE(o.invoked(), 1);
1899 QCOMPARE(o.actuals().count(), 0);
1902 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1903 QCOMPARE(o.error(), false);
1904 QCOMPARE(o.invoked(), 2);
1905 QCOMPARE(o.actuals().count(), 0);
1909 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1910 QVERIFY(!ret.IsEmpty());
1911 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1912 QCOMPARE(o.error(), false);
1913 QCOMPARE(o.invoked(), 3);
1914 QCOMPARE(o.actuals().count(), 0);
1919 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1920 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1921 QCOMPARE(o.error(), false);
1922 QCOMPARE(o.invoked(), 4);
1923 QCOMPARE(o.actuals().count(), 0);
1927 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1928 QCOMPARE(o.error(), false);
1929 QCOMPARE(o.invoked(), 5);
1930 QCOMPARE(o.actuals().count(), 0);
1934 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1935 QVERIFY(ret->IsString());
1936 QCOMPARE(engine->toString(ret), QString("Hello world"));
1937 QCOMPARE(o.error(), false);
1938 QCOMPARE(o.invoked(), 6);
1939 QCOMPARE(o.actuals().count(), 0);
1943 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1944 QCOMPARE(o.error(), false);
1945 QCOMPARE(o.invoked(), 7);
1946 QCOMPARE(o.actuals().count(), 0);
1950 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1951 QCOMPARE(o.error(), false);
1952 QCOMPARE(o.invoked(), 8);
1953 QCOMPARE(o.actuals().count(), 1);
1954 QCOMPARE(o.actuals().at(0), QVariant(94));
1957 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1958 QCOMPARE(o.error(), false);
1959 QCOMPARE(o.invoked(), 8);
1960 QCOMPARE(o.actuals().count(), 1);
1961 QCOMPARE(o.actuals().at(0), QVariant(94));
1964 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1965 QCOMPARE(o.error(), false);
1966 QCOMPARE(o.invoked(), 8);
1967 QCOMPARE(o.actuals().count(), 1);
1968 QCOMPARE(o.actuals().at(0), QVariant(0));
1971 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1972 QCOMPARE(o.error(), false);
1973 QCOMPARE(o.invoked(), 8);
1974 QCOMPARE(o.actuals().count(), 1);
1975 QCOMPARE(o.actuals().at(0), QVariant(0));
1978 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1979 QCOMPARE(o.error(), false);
1980 QCOMPARE(o.invoked(), 8);
1981 QCOMPARE(o.actuals().count(), 1);
1982 QCOMPARE(o.actuals().at(0), QVariant(0));
1985 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1986 QCOMPARE(o.error(), false);
1987 QCOMPARE(o.invoked(), 8);
1988 QCOMPARE(o.actuals().count(), 1);
1989 QCOMPARE(o.actuals().at(0), QVariant(0));
1992 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1993 QCOMPARE(o.error(), false);
1994 QCOMPARE(o.invoked(), 9);
1995 QCOMPARE(o.actuals().count(), 2);
1996 QCOMPARE(o.actuals().at(0), QVariant(122));
1997 QCOMPARE(o.actuals().at(1), QVariant(9));
2000 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2001 QCOMPARE(o.error(), false);
2002 QCOMPARE(o.invoked(), 10);
2003 QCOMPARE(o.actuals().count(), 1);
2004 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2007 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2008 QCOMPARE(o.error(), false);
2009 QCOMPARE(o.invoked(), 10);
2010 QCOMPARE(o.actuals().count(), 1);
2011 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2014 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2015 QCOMPARE(o.error(), false);
2016 QCOMPARE(o.invoked(), 10);
2017 QCOMPARE(o.actuals().count(), 1);
2018 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2021 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2022 QCOMPARE(o.error(), false);
2023 QCOMPARE(o.invoked(), 10);
2024 QCOMPARE(o.actuals().count(), 1);
2025 QCOMPARE(o.actuals().at(0), QVariant(0));
2028 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2029 QCOMPARE(o.error(), false);
2030 QCOMPARE(o.invoked(), 10);
2031 QCOMPARE(o.actuals().count(), 1);
2032 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2035 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2036 QCOMPARE(o.error(), false);
2037 QCOMPARE(o.invoked(), 10);
2038 QCOMPARE(o.actuals().count(), 1);
2039 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2042 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2043 QCOMPARE(o.error(), false);
2044 QCOMPARE(o.invoked(), 11);
2045 QCOMPARE(o.actuals().count(), 1);
2046 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2049 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2050 QCOMPARE(o.error(), false);
2051 QCOMPARE(o.invoked(), 11);
2052 QCOMPARE(o.actuals().count(), 1);
2053 QCOMPARE(o.actuals().at(0), QVariant("19"));
2057 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2058 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2059 QCOMPARE(o.error(), false);
2060 QCOMPARE(o.invoked(), 11);
2061 QCOMPARE(o.actuals().count(), 1);
2062 QCOMPARE(o.actuals().at(0), QVariant(expected));
2066 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2067 QCOMPARE(o.error(), false);
2068 QCOMPARE(o.invoked(), 11);
2069 QCOMPARE(o.actuals().count(), 1);
2070 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2073 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2074 QCOMPARE(o.error(), false);
2075 QCOMPARE(o.invoked(), 11);
2076 QCOMPARE(o.actuals().count(), 1);
2077 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2080 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2081 QCOMPARE(o.error(), false);
2082 QCOMPARE(o.invoked(), 12);
2083 QCOMPARE(o.actuals().count(), 1);
2084 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2087 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2088 QCOMPARE(o.error(), false);
2089 QCOMPARE(o.invoked(), 12);
2090 QCOMPARE(o.actuals().count(), 1);
2091 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2094 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2095 QCOMPARE(o.error(), false);
2096 QCOMPARE(o.invoked(), 12);
2097 QCOMPARE(o.actuals().count(), 1);
2098 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2101 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2102 QCOMPARE(o.error(), false);
2103 QCOMPARE(o.invoked(), 12);
2104 QCOMPARE(o.actuals().count(), 1);
2105 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2108 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2109 QCOMPARE(o.error(), false);
2110 QCOMPARE(o.invoked(), 12);
2111 QCOMPARE(o.actuals().count(), 1);
2112 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2115 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2116 QCOMPARE(o.error(), false);
2117 QCOMPARE(o.invoked(), 12);
2118 QCOMPARE(o.actuals().count(), 1);
2119 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2122 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2123 QCOMPARE(o.error(), false);
2124 QCOMPARE(o.invoked(), 13);
2125 QCOMPARE(o.actuals().count(), 1);
2126 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2129 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2130 QCOMPARE(o.error(), false);
2131 QCOMPARE(o.invoked(), 13);
2132 QCOMPARE(o.actuals().count(), 1);
2133 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2136 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2137 QCOMPARE(o.error(), false);
2138 QCOMPARE(o.invoked(), 13);
2139 QCOMPARE(o.actuals().count(), 1);
2140 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2143 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2144 QCOMPARE(o.error(), false);
2145 QCOMPARE(o.invoked(), 13);
2146 QCOMPARE(o.actuals().count(), 1);
2147 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2150 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2151 QCOMPARE(o.error(), false);
2152 QCOMPARE(o.invoked(), 13);
2153 QCOMPARE(o.actuals().count(), 1);
2154 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2157 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2158 QCOMPARE(o.error(), false);
2159 QCOMPARE(o.invoked(), 14);
2160 QCOMPARE(o.actuals().count(), 1);
2161 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2164 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2165 QCOMPARE(o.error(), false);
2166 QCOMPARE(o.invoked(), 14);
2167 QCOMPARE(o.actuals().count(), 1);
2168 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2171 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2172 QCOMPARE(o.error(), false);
2173 QCOMPARE(o.invoked(), 14);
2174 QCOMPARE(o.actuals().count(), 1);
2175 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2178 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2179 QCOMPARE(o.error(), false);
2180 QCOMPARE(o.invoked(), 14);
2181 QCOMPARE(o.actuals().count(), 1);
2182 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2185 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2186 QCOMPARE(o.error(), false);
2187 QCOMPARE(o.invoked(), 15);
2188 QCOMPARE(o.actuals().count(), 2);
2189 QCOMPARE(o.actuals().at(0), QVariant(4));
2190 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2193 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2194 QCOMPARE(o.error(), false);
2195 QCOMPARE(o.invoked(), 15);
2196 QCOMPARE(o.actuals().count(), 2);
2197 QCOMPARE(o.actuals().at(0), QVariant(8));
2198 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2201 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2202 QCOMPARE(o.error(), false);
2203 QCOMPARE(o.invoked(), 15);
2204 QCOMPARE(o.actuals().count(), 2);
2205 QCOMPARE(o.actuals().at(0), QVariant(3));
2206 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2209 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2210 QCOMPARE(o.error(), false);
2211 QCOMPARE(o.invoked(), 15);
2212 QCOMPARE(o.actuals().count(), 2);
2213 QCOMPARE(o.actuals().at(0), QVariant(44));
2214 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2217 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2218 QCOMPARE(o.error(), false);
2219 QCOMPARE(o.invoked(), -1);
2220 QCOMPARE(o.actuals().count(), 0);
2223 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2224 QCOMPARE(o.error(), false);
2225 QCOMPARE(o.invoked(), 16);
2226 QCOMPARE(o.actuals().count(), 1);
2227 QCOMPARE(o.actuals().at(0), QVariant(10));
2230 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2231 QCOMPARE(o.error(), false);
2232 QCOMPARE(o.invoked(), 17);
2233 QCOMPARE(o.actuals().count(), 2);
2234 QCOMPARE(o.actuals().at(0), QVariant(10));
2235 QCOMPARE(o.actuals().at(1), QVariant(11));
2238 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2239 QCOMPARE(o.error(), false);
2240 QCOMPARE(o.invoked(), 18);
2241 QCOMPARE(o.actuals().count(), 1);
2242 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2245 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2246 QCOMPARE(o.error(), false);
2247 QCOMPARE(o.invoked(), 19);
2248 QCOMPARE(o.actuals().count(), 1);
2249 QCOMPARE(o.actuals().at(0), QVariant(9));
2252 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2253 QCOMPARE(o.error(), false);
2254 QCOMPARE(o.invoked(), 20);
2255 QCOMPARE(o.actuals().count(), 2);
2256 QCOMPARE(o.actuals().at(0), QVariant(10));
2257 QCOMPARE(o.actuals().at(1), QVariant(19));
2260 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2261 QCOMPARE(o.error(), false);
2262 QCOMPARE(o.invoked(), 20);
2263 QCOMPARE(o.actuals().count(), 2);
2264 QCOMPARE(o.actuals().at(0), QVariant(10));
2265 QCOMPARE(o.actuals().at(1), QVariant(13));
2268 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2269 QCOMPARE(o.error(), false);
2270 QCOMPARE(o.invoked(), -3);
2271 QCOMPARE(o.actuals().count(), 1);
2272 QCOMPARE(o.actuals().at(0), QVariant(9));
2275 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2276 QCOMPARE(o.error(), false);
2277 QCOMPARE(o.invoked(), 21);
2278 QCOMPARE(o.actuals().count(), 2);
2279 QCOMPARE(o.actuals().at(0), QVariant(9));
2280 QCOMPARE(o.actuals().at(1), QVariant());
2283 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2284 QCOMPARE(o.error(), false);
2285 QCOMPARE(o.invoked(), 21);
2286 QCOMPARE(o.actuals().count(), 2);
2287 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2288 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2291 // QTBUG-13047 (check that you can pass registered object types as args)
2292 void tst_qdeclarativeecmascript::invokableObjectArg()
2294 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2296 QObject *o = component.create();
2298 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2300 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2305 // QTBUG-13047 (check that you can return registered object types from methods)
2306 void tst_qdeclarativeecmascript::invokableObjectRet()
2308 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2310 QObject *o = component.create();
2312 QCOMPARE(o->property("test").toBool(), true);
2317 void tst_qdeclarativeecmascript::listToVariant()
2319 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2321 MyQmlContainer container;
2323 QDeclarativeContext context(engine.rootContext());
2324 context.setContextObject(&container);
2326 QObject *object = component.create(&context);
2327 QVERIFY(object != 0);
2329 QVariant v = object->property("test");
2330 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2331 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2337 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2338 void tst_qdeclarativeecmascript::listAssignment()
2340 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2341 QObject *obj = component.create();
2342 QCOMPARE(obj->property("list1length").toInt(), 2);
2343 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2344 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2345 QCOMPARE(list1.count(&list1), list2.count(&list2));
2346 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2347 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2352 void tst_qdeclarativeecmascript::multiEngineObject()
2355 obj.setStringProperty("Howdy planet");
2357 QDeclarativeEngine e1;
2358 e1.rootContext()->setContextProperty("thing", &obj);
2359 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2361 QDeclarativeEngine e2;
2362 e2.rootContext()->setContextProperty("thing", &obj);
2363 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2365 QObject *o1 = c1.create();
2366 QObject *o2 = c2.create();
2368 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2369 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2375 // Test that references to QObjects are cleanup when the object is destroyed
2376 void tst_qdeclarativeecmascript::deletedObject()
2378 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2380 QObject *object = component.create();
2382 QCOMPARE(object->property("test1").toBool(), true);
2383 QCOMPARE(object->property("test2").toBool(), true);
2384 QCOMPARE(object->property("test3").toBool(), true);
2385 QCOMPARE(object->property("test4").toBool(), true);
2390 void tst_qdeclarativeecmascript::attachedPropertyScope()
2392 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2394 QObject *object = component.create();
2395 QVERIFY(object != 0);
2397 MyQmlAttachedObject *attached =
2398 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2399 QVERIFY(attached != 0);
2401 QCOMPARE(object->property("value2").toInt(), 0);
2403 attached->emitMySignal();
2405 QCOMPARE(object->property("value2").toInt(), 9);
2410 void tst_qdeclarativeecmascript::scriptConnect()
2413 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2415 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2416 QVERIFY(object != 0);
2418 QCOMPARE(object->property("test").toBool(), false);
2419 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2420 QCOMPARE(object->property("test").toBool(), true);
2426 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2428 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2429 QVERIFY(object != 0);
2431 QCOMPARE(object->property("test").toBool(), false);
2432 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2433 QCOMPARE(object->property("test").toBool(), true);
2439 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2441 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2442 QVERIFY(object != 0);
2444 QCOMPARE(object->property("test").toBool(), false);
2445 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2446 QCOMPARE(object->property("test").toBool(), true);
2452 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2454 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2455 QVERIFY(object != 0);
2457 QCOMPARE(object->methodCalled(), false);
2458 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2459 QCOMPARE(object->methodCalled(), true);
2465 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2467 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2468 QVERIFY(object != 0);
2470 QCOMPARE(object->methodCalled(), false);
2471 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2472 QCOMPARE(object->methodCalled(), true);
2478 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2480 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2481 QVERIFY(object != 0);
2483 QCOMPARE(object->property("test").toInt(), 0);
2484 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2485 QCOMPARE(object->property("test").toInt(), 2);
2491 void tst_qdeclarativeecmascript::scriptDisconnect()
2494 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2496 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2497 QVERIFY(object != 0);
2499 QCOMPARE(object->property("test").toInt(), 0);
2500 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2501 QCOMPARE(object->property("test").toInt(), 1);
2502 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2503 QCOMPARE(object->property("test").toInt(), 2);
2504 emit object->basicSignal();
2505 QCOMPARE(object->property("test").toInt(), 2);
2506 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2507 QCOMPARE(object->property("test").toInt(), 2);
2513 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2515 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2516 QVERIFY(object != 0);
2518 QCOMPARE(object->property("test").toInt(), 0);
2519 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2520 QCOMPARE(object->property("test").toInt(), 1);
2521 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2522 QCOMPARE(object->property("test").toInt(), 2);
2523 emit object->basicSignal();
2524 QCOMPARE(object->property("test").toInt(), 2);
2525 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2526 QCOMPARE(object->property("test").toInt(), 2);
2532 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2534 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2535 QVERIFY(object != 0);
2537 QCOMPARE(object->property("test").toInt(), 0);
2538 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2539 QCOMPARE(object->property("test").toInt(), 1);
2540 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2541 QCOMPARE(object->property("test").toInt(), 2);
2542 emit object->basicSignal();
2543 QCOMPARE(object->property("test").toInt(), 2);
2544 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2545 QCOMPARE(object->property("test").toInt(), 3);
2550 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2552 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2553 QVERIFY(object != 0);
2555 QCOMPARE(object->property("test").toInt(), 0);
2556 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2557 QCOMPARE(object->property("test").toInt(), 1);
2558 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2559 QCOMPARE(object->property("test").toInt(), 2);
2560 emit object->basicSignal();
2561 QCOMPARE(object->property("test").toInt(), 2);
2562 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2563 QCOMPARE(object->property("test").toInt(), 3);
2569 class OwnershipObject : public QObject
2573 OwnershipObject() { object = new QObject; }
2575 QPointer<QObject> object;
2578 QObject *getObject() { return object; }
2581 void tst_qdeclarativeecmascript::ownership()
2583 OwnershipObject own;
2584 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2585 context->setContextObject(&own);
2588 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2590 QVERIFY(own.object != 0);
2592 QObject *object = component.create(context);
2594 engine.collectGarbage();
2596 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2598 QVERIFY(own.object == 0);
2603 own.object = new QObject(&own);
2606 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2608 QVERIFY(own.object != 0);
2610 QObject *object = component.create(context);
2612 engine.collectGarbage();
2614 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2616 QVERIFY(own.object != 0);
2624 class CppOwnershipReturnValue : public QObject
2628 CppOwnershipReturnValue() : value(0) {}
2629 ~CppOwnershipReturnValue() { delete value; }
2631 Q_INVOKABLE QObject *create() {
2632 value = new QObject;
2633 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2637 Q_INVOKABLE MyQmlObject *createQmlObject() {
2638 MyQmlObject *rv = new MyQmlObject;
2643 QPointer<QObject> value;
2647 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2648 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2650 CppOwnershipReturnValue source;
2653 QDeclarativeEngine engine;
2654 engine.rootContext()->setContextProperty("source", &source);
2656 QVERIFY(source.value == 0);
2658 QDeclarativeComponent component(&engine);
2659 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2661 QObject *object = component.create();
2663 QVERIFY(object != 0);
2664 QVERIFY(source.value != 0);
2669 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2671 QVERIFY(source.value != 0);
2675 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2677 CppOwnershipReturnValue source;
2680 QDeclarativeEngine engine;
2681 engine.rootContext()->setContextProperty("source", &source);
2683 QVERIFY(source.value == 0);
2685 QDeclarativeComponent component(&engine);
2686 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2688 QObject *object = component.create();
2690 QVERIFY(object != 0);
2691 QVERIFY(source.value != 0);
2696 engine.collectGarbage();
2697 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2699 QVERIFY(source.value == 0);
2702 class QListQObjectMethodsObject : public QObject
2706 QListQObjectMethodsObject() {
2707 m_objects.append(new MyQmlObject());
2708 m_objects.append(new MyQmlObject());
2711 ~QListQObjectMethodsObject() {
2712 qDeleteAll(m_objects);
2716 QList<QObject *> getObjects() { return m_objects; }
2719 QList<QObject *> m_objects;
2722 // Tests that returning a QList<QObject*> from a method works
2723 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2725 QListQObjectMethodsObject obj;
2726 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2727 context->setContextObject(&obj);
2729 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2731 QObject *object = component.create(context);
2733 QCOMPARE(object->property("test").toInt(), 2);
2734 QCOMPARE(object->property("test2").toBool(), true);
2741 void tst_qdeclarativeecmascript::strictlyEquals()
2743 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2745 QObject *object = component.create();
2746 QVERIFY(object != 0);
2748 QCOMPARE(object->property("test1").toBool(), true);
2749 QCOMPARE(object->property("test2").toBool(), true);
2750 QCOMPARE(object->property("test3").toBool(), true);
2751 QCOMPARE(object->property("test4").toBool(), true);
2752 QCOMPARE(object->property("test5").toBool(), true);
2753 QCOMPARE(object->property("test6").toBool(), true);
2754 QCOMPARE(object->property("test7").toBool(), true);
2755 QCOMPARE(object->property("test8").toBool(), true);
2760 void tst_qdeclarativeecmascript::compiled()
2762 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2764 QObject *object = component.create();
2765 QVERIFY(object != 0);
2767 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2768 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2769 QCOMPARE(object->property("test3").toBool(), true);
2770 QCOMPARE(object->property("test4").toBool(), false);
2771 QCOMPARE(object->property("test5").toBool(), false);
2772 QCOMPARE(object->property("test6").toBool(), true);
2774 QCOMPARE(object->property("test7").toInt(), 185);
2775 QCOMPARE(object->property("test8").toInt(), 167);
2776 QCOMPARE(object->property("test9").toBool(), true);
2777 QCOMPARE(object->property("test10").toBool(), false);
2778 QCOMPARE(object->property("test11").toBool(), false);
2779 QCOMPARE(object->property("test12").toBool(), true);
2781 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2782 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2783 QCOMPARE(object->property("test15").toBool(), false);
2784 QCOMPARE(object->property("test16").toBool(), true);
2786 QCOMPARE(object->property("test17").toInt(), 5);
2787 QCOMPARE(object->property("test18").toReal(), qreal(176));
2788 QCOMPARE(object->property("test19").toInt(), 7);
2789 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2790 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2791 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2792 QCOMPARE(object->property("test23").toBool(), true);
2793 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2794 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2799 // Test that numbers assigned in bindings as strings work consistently
2800 void tst_qdeclarativeecmascript::numberAssignment()
2802 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2804 QObject *object = component.create();
2805 QVERIFY(object != 0);
2807 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2808 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2809 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2810 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2811 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2813 QCOMPARE(object->property("test5"), QVariant((int)7));
2814 QCOMPARE(object->property("test6"), QVariant((int)7));
2815 QCOMPARE(object->property("test7"), QVariant((int)6));
2816 QCOMPARE(object->property("test8"), QVariant((int)6));
2818 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2819 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2820 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2821 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2826 void tst_qdeclarativeecmascript::propertySplicing()
2828 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2830 QObject *object = component.create();
2831 QVERIFY(object != 0);
2833 QCOMPARE(object->property("test").toBool(), true);
2839 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2841 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2843 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2844 QVERIFY(object != 0);
2846 MyQmlObject::MyType type;
2847 type.value = 0x8971123;
2848 emit object->signalWithUnknownType(type);
2850 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2852 QCOMPARE(result.value, type.value);
2858 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2860 QTest::addColumn<QString>("expression");
2861 QTest::addColumn<QString>("compare");
2863 QString compareStrict("(function(a, b) { return a === b; })");
2864 QTest::newRow("true") << "true" << compareStrict;
2865 QTest::newRow("undefined") << "undefined" << compareStrict;
2866 QTest::newRow("null") << "null" << compareStrict;
2867 QTest::newRow("123") << "123" << compareStrict;
2868 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2870 QString comparePropertiesStrict(
2872 " if (typeof b != 'object')"
2874 " var props = Object.getOwnPropertyNames(b);"
2875 " for (var i = 0; i < props.length; ++i) {"
2876 " var p = props[i];"
2877 " return arguments.callee(a[p], b[p]);"
2880 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2881 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2884 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2886 QFETCH(QString, expression);
2887 QFETCH(QString, compare);
2889 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2890 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2891 QVERIFY(object != 0);
2893 QJSValue value = engine.evaluate(expression);
2894 QVERIFY(!engine.hasUncaughtException());
2895 object->setProperty("expression", expression);
2896 object->setProperty("compare", compare);
2897 object->setProperty("pass", false);
2899 emit object->signalWithVariant(QVariant::fromValue(value));
2900 QVERIFY(object->property("pass").toBool());
2903 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2905 signalWithJSValueInVariant_data();
2908 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2910 QFETCH(QString, expression);
2911 QFETCH(QString, compare);
2913 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2914 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2915 QVERIFY(object != 0);
2918 QJSValue value = engine2.evaluate(expression);
2919 QVERIFY(!engine2.hasUncaughtException());
2920 object->setProperty("expression", expression);
2921 object->setProperty("compare", compare);
2922 object->setProperty("pass", false);
2924 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2925 emit object->signalWithVariant(QVariant::fromValue(value));
2926 QVERIFY(!object->property("pass").toBool());
2929 void tst_qdeclarativeecmascript::moduleApi_data()
2931 QTest::addColumn<QUrl>("testfile");
2932 QTest::addColumn<QString>("errorMessage");
2933 QTest::addColumn<QStringList>("warningMessages");
2934 QTest::addColumn<QStringList>("readProperties");
2935 QTest::addColumn<QVariantList>("readExpectedValues");
2936 QTest::addColumn<QStringList>("writeProperties");
2937 QTest::addColumn<QVariantList>("writeValues");
2938 QTest::addColumn<QStringList>("readBackProperties");
2939 QTest::addColumn<QVariantList>("readBackExpectedValues");
2941 QTest::newRow("qobject, register + read + method")
2942 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2945 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2946 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2947 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2953 QTest::newRow("script, register + read")
2954 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2957 << (QStringList() << "scriptTest")
2958 << (QVariantList() << 13)
2964 QTest::newRow("qobject, caching + read")
2965 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2968 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2969 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2975 QTest::newRow("script, caching + read")
2976 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2979 << (QStringList() << "scriptTest")
2980 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2986 QTest::newRow("qobject, writing + readonly constraints")
2987 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2989 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2990 << (QStringList() << "readOnlyProperty" << "writableProperty")
2991 << (QVariantList() << 20 << 50)
2992 << (QStringList() << "firstProperty" << "writableProperty")
2993 << (QVariantList() << 30 << 30)
2994 << (QStringList() << "readOnlyProperty" << "writableProperty")
2995 << (QVariantList() << 20 << 30);
2997 QTest::newRow("script, writing + readonly constraints")
2998 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
3000 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3001 << (QStringList() << "readBack" << "unchanged")
3002 << (QVariantList() << 13 << 42)
3003 << (QStringList() << "firstProperty" << "secondProperty")
3004 << (QVariantList() << 30 << 30)
3005 << (QStringList() << "readBack" << "unchanged")
3006 << (QVariantList() << 30 << 42);
3008 QTest::newRow("qobject module API enum values in JS")
3009 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3012 << (QStringList() << "enumValue" << "enumMethod")
3013 << (QVariantList() << 42 << 30)
3019 QTest::newRow("qobject, invalid major version fail")
3020 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3021 << QString("QDeclarativeComponent: Component is not ready")
3030 QTest::newRow("qobject, invalid minor version fail")
3031 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3032 << QString("QDeclarativeComponent: Component is not ready")
3042 void tst_qdeclarativeecmascript::moduleApi()
3044 QFETCH(QUrl, testfile);
3045 QFETCH(QString, errorMessage);
3046 QFETCH(QStringList, warningMessages);
3047 QFETCH(QStringList, readProperties);
3048 QFETCH(QVariantList, readExpectedValues);
3049 QFETCH(QStringList, writeProperties);
3050 QFETCH(QVariantList, writeValues);
3051 QFETCH(QStringList, readBackProperties);
3052 QFETCH(QVariantList, readBackExpectedValues);
3054 QDeclarativeComponent component(&engine, testfile);
3056 if (!errorMessage.isEmpty())
3057 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3059 if (warningMessages.size())
3060 foreach (const QString &warning, warningMessages)
3061 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3063 QObject *object = component.create();
3064 if (!errorMessage.isEmpty()) {
3065 QVERIFY(object == 0);
3067 QVERIFY(object != 0);
3068 for (int i = 0; i < readProperties.size(); ++i)
3069 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3070 for (int i = 0; i < writeProperties.size(); ++i)
3071 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3072 for (int i = 0; i < readBackProperties.size(); ++i)
3073 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3078 void tst_qdeclarativeecmascript::importScripts_data()
3080 QTest::addColumn<QUrl>("testfile");
3081 QTest::addColumn<QString>("errorMessage");
3082 QTest::addColumn<QStringList>("warningMessages");
3083 QTest::addColumn<QStringList>("propertyNames");
3084 QTest::addColumn<QVariantList>("propertyValues");
3086 QTest::newRow("basic functionality")
3087 << TEST_FILE("jsimport/testImport.qml")
3090 << (QStringList() << QLatin1String("importedScriptStringValue")
3091 << QLatin1String("importedScriptFunctionValue")
3092 << QLatin1String("importedModuleAttachedPropertyValue")
3093 << QLatin1String("importedModuleEnumValue"))
3094 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3099 QTest::newRow("import scoping")
3100 << TEST_FILE("jsimport/testImportScoping.qml")
3103 << (QStringList() << QLatin1String("componentError"))
3104 << (QVariantList() << QVariant(5));
3106 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3107 << TEST_FILE("jsimportfail/failOne.qml")
3109 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3110 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3111 << (QVariantList() << QVariant(QString()));
3113 QTest::newRow("javascript imports in an import should be private to the import scope")
3114 << TEST_FILE("jsimportfail/failTwo.qml")
3116 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3117 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3118 << (QVariantList() << QVariant(QString()));
3120 QTest::newRow("module imports in an import should be private to the import scope")
3121 << TEST_FILE("jsimportfail/failThree.qml")
3123 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3124 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3125 << (QVariantList() << QVariant(false));
3127 QTest::newRow("typenames in an import should be private to the import scope")
3128 << TEST_FILE("jsimportfail/failFour.qml")
3130 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3131 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3132 << (QVariantList() << QVariant(0));
3134 QTest::newRow("import with imports has it's own activation scope")
3135 << TEST_FILE("jsimportfail/failFive.qml")
3137 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3138 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3139 << (QStringList() << QLatin1String("componentError"))
3140 << (QVariantList() << QVariant(0));
3142 QTest::newRow("import pragma library script")
3143 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3146 << (QStringList() << QLatin1String("testValue"))
3147 << (QVariantList() << QVariant(31));
3149 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3150 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3153 << (QStringList() << QLatin1String("testValue"))
3154 << (QVariantList() << QVariant(0));
3156 QTest::newRow("import pragma library script which has an import")
3157 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3160 << (QStringList() << QLatin1String("testValue"))
3161 << (QVariantList() << QVariant(55));
3163 QTest::newRow("import pragma library script which has a pragma library import")
3164 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3167 << (QStringList() << QLatin1String("testValue"))
3168 << (QVariantList() << QVariant(18));
3171 void tst_qdeclarativeecmascript::importScripts()
3173 QFETCH(QUrl, testfile);
3174 QFETCH(QString, errorMessage);
3175 QFETCH(QStringList, warningMessages);
3176 QFETCH(QStringList, propertyNames);
3177 QFETCH(QVariantList, propertyValues);
3179 QDeclarativeComponent component(&engine, testfile);
3181 if (!errorMessage.isEmpty())
3182 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3184 if (warningMessages.size())
3185 foreach (const QString &warning, warningMessages)
3186 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3188 QObject *object = component.create();
3189 if (!errorMessage.isEmpty()) {
3190 QVERIFY(object == 0);
3192 QVERIFY(object != 0);
3193 for (int i = 0; i < propertyNames.size(); ++i)
3194 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3199 void tst_qdeclarativeecmascript::scarceResources()
3201 QPixmap origPixmap(100, 100);
3202 origPixmap.fill(Qt::blue);
3204 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3205 ScarceResourceObject *eo = 0;
3206 QObject *object = 0;
3208 // in the following three cases, the instance created from the component
3209 // has a property which is a copy of the scarce resource; hence, the
3210 // resource should NOT be detached prior to deletion of the object instance,
3211 // unless the resource is destroyed explicitly.
3212 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3213 object = component.create();
3214 QVERIFY(object != 0);
3215 QVERIFY(object->property("scarceResourceCopy").isValid());
3216 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3217 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3218 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3219 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3222 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3223 object = componentTwo.create();
3224 QVERIFY(object != 0);
3225 QVERIFY(object->property("scarceResourceCopy").isValid());
3226 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3227 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3228 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3229 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3232 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3233 object = componentThree.create();
3234 QVERIFY(object != 0);
3235 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3236 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3237 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3238 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3241 // in the following three cases, no other copy should exist in memory,
3242 // and so it should be detached (unless explicitly preserved).
3243 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3244 object = componentFour.create();
3245 QVERIFY(object != 0);
3246 QVERIFY(object->property("scarceResourceTest").isValid());
3247 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3248 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3249 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3250 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3253 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3254 object = componentFive.create();
3255 QVERIFY(object != 0);
3256 QVERIFY(object->property("scarceResourceTest").isValid());
3257 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3258 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3259 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3260 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3263 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3264 object = componentSix.create();
3265 QVERIFY(object != 0);
3266 QVERIFY(object->property("scarceResourceTest").isValid());
3267 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3268 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3269 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3270 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3273 // test that scarce resources are handled correctly for imports
3274 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3275 object = componentSeven.create();
3276 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3277 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3280 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3281 object = componentEight.create();
3282 QVERIFY(object != 0);
3283 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3284 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3287 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3288 object = componentNine.create();
3289 QVERIFY(object != 0);
3290 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3291 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3292 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3293 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3294 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3295 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3298 // test that scarce resources are handled properly in signal invocation
3299 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3300 object = componentTen.create();
3301 QVERIFY(object != 0);
3302 QObject *srsc = object->findChild<QObject*>("srsc");
3304 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3305 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3306 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3307 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3308 QMetaObject::invokeMethod(srsc, "testSignal");
3309 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3310 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3311 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3312 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3313 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3314 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3315 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3316 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3317 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3318 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3321 // test that scarce resources are handled properly from js functions in qml files
3322 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3323 object = componentEleven.create();
3324 QVERIFY(object != 0);
3325 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, 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 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3329 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3330 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3331 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3332 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3333 QMetaObject::invokeMethod(object, "releaseScarceResource");
3334 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3335 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3336 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3337 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3340 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3341 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3342 object = componentTwelve.create();
3343 QVERIFY(object != 0);
3344 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3345 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3346 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3347 QString srp_name = object->property("srp_name").toString();
3348 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3349 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3350 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3351 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3352 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3353 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3354 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3358 void tst_qdeclarativeecmascript::propertyChangeSlots()
3360 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3361 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3362 QObject *object = component.create();
3363 QVERIFY(object != 0);
3366 // ensure that invalid property names fail properly.
3367 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3368 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3369 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3370 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3371 object = e1.create();
3372 QVERIFY(object == 0);
3375 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3376 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3377 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3378 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3379 object = e2.create();
3380 QVERIFY(object == 0);
3383 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3384 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3385 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3386 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3387 object = e3.create();
3388 QVERIFY(object == 0);
3391 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3392 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3393 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3394 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3395 object = e4.create();
3396 QVERIFY(object == 0);
3400 void tst_qdeclarativeecmascript::propertyVar_data()
3402 QTest::addColumn<QUrl>("qmlFile");
3405 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3406 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3407 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3408 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3409 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3410 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3411 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3412 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3413 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3416 void tst_qdeclarativeecmascript::propertyVar()
3418 QFETCH(QUrl, qmlFile);
3420 QDeclarativeComponent component(&engine, qmlFile);
3421 QObject *object = component.create();
3422 QVERIFY(object != 0);
3424 QCOMPARE(object->property("test").toBool(), true);
3429 // Tests that we can write QVariant values to var properties from C++
3430 void tst_qdeclarativeecmascript::propertyVarCpp()
3432 QObject *object = 0;
3434 // ensure that writing to and reading from a var property from cpp works as required.
3435 // Literal values stored in var properties can be read and written as QVariants
3436 // of a specific type, whereas object values are read as QVariantMaps.
3437 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3438 object = component.create();
3439 QVERIFY(object != 0);
3440 // assign int to property var that currently has int assigned
3441 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3442 QCOMPARE(object->property("varBound"), QVariant(15));
3443 QCOMPARE(object->property("intBound"), QVariant(15));
3444 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3445 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3446 // assign string to property var that current has bool assigned
3447 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3448 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3449 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3450 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3451 // now enforce behaviour when accessing JavaScript objects from cpp.
3452 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3456 static void gc(QDeclarativeEngine &engine)
3458 engine.collectGarbage();
3459 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3462 void tst_qdeclarativeecmascript::propertyVarOwnership()
3464 // Referenced JS objects are not collected
3466 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3467 QObject *object = component.create();
3468 QVERIFY(object != 0);
3469 QCOMPARE(object->property("test").toBool(), false);
3470 QMetaObject::invokeMethod(object, "runTest");
3471 QCOMPARE(object->property("test").toBool(), true);
3474 // Referenced JS objects are not collected
3476 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3477 QObject *object = component.create();
3478 QVERIFY(object != 0);
3479 QCOMPARE(object->property("test").toBool(), false);
3480 QMetaObject::invokeMethod(object, "runTest");
3481 QCOMPARE(object->property("test").toBool(), true);
3484 // Qt objects are not collected until they've been dereferenced
3486 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3487 QObject *object = component.create();
3488 QVERIFY(object != 0);
3490 QCOMPARE(object->property("test2").toBool(), false);
3491 QCOMPARE(object->property("test2").toBool(), false);
3493 QMetaObject::invokeMethod(object, "runTest");
3494 QCOMPARE(object->property("test1").toBool(), true);
3496 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3497 QVERIFY(!referencedObject.isNull());
3499 QVERIFY(!referencedObject.isNull());
3501 QMetaObject::invokeMethod(object, "runTest2");
3502 QCOMPARE(object->property("test2").toBool(), true);
3504 QVERIFY(referencedObject.isNull());
3508 // Self reference does not prevent Qt object collection
3510 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3511 QObject *object = component.create();
3512 QVERIFY(object != 0);
3514 QCOMPARE(object->property("test").toBool(), true);
3516 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3517 QVERIFY(!referencedObject.isNull());
3519 QVERIFY(!referencedObject.isNull());
3521 QMetaObject::invokeMethod(object, "runTest");
3523 QVERIFY(referencedObject.isNull());
3529 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3531 // The childObject has a reference to a different QObject. We want to ensure
3532 // that the different item will not be cleaned up until required. IE, the childObject
3533 // has implicit ownership of the constructed QObject.
3534 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3535 QObject *object = component.create();
3536 QVERIFY(object != 0);
3537 QMetaObject::invokeMethod(object, "assignCircular");
3538 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3539 QObject *rootObject = object->property("vp").value<QObject*>();
3540 QVERIFY(rootObject != 0);
3541 QObject *childObject = rootObject->findChild<QObject*>("text");
3542 QVERIFY(childObject != 0);
3543 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3544 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3545 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3546 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3547 QVERIFY(!qobjectGuard.isNull());
3548 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3549 QVERIFY(!qobjectGuard.isNull());
3550 QMetaObject::invokeMethod(object, "deassignCircular");
3551 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3552 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3556 void tst_qdeclarativeecmascript::propertyVarReparent()
3558 // ensure that nothing breaks if we re-parent objects
3559 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3560 QObject *object = component.create();
3561 QVERIFY(object != 0);
3562 QMetaObject::invokeMethod(object, "assignVarProp");
3563 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3564 QObject *rect = object->property("vp").value<QObject*>();
3565 QObject *text = rect->findChild<QObject*>("textOne");
3566 QObject *text2 = rect->findChild<QObject*>("textTwo");
3567 QWeakPointer<QObject> rectGuard(rect);
3568 QWeakPointer<QObject> textGuard(text);
3569 QWeakPointer<QObject> text2Guard(text2);
3570 QVERIFY(!rectGuard.isNull());
3571 QVERIFY(!textGuard.isNull());
3572 QVERIFY(!text2Guard.isNull());
3573 QCOMPARE(text->property("textCanary").toInt(), 11);
3574 QCOMPARE(text2->property("textCanary").toInt(), 12);
3575 // now construct an image which we will reparent.
3576 QMetaObject::invokeMethod(text2, "constructQObject");
3577 QObject *image = text2->property("vp").value<QObject*>();
3578 QWeakPointer<QObject> imageGuard(image);
3579 QVERIFY(!imageGuard.isNull());
3580 QCOMPARE(image->property("imageCanary").toInt(), 13);
3581 // now reparent the "Image" object (currently, it has JS ownership)
3582 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3583 QMetaObject::invokeMethod(text2, "deassignVp");
3584 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3585 QCOMPARE(text->property("textCanary").toInt(), 11);
3586 QCOMPARE(text2->property("textCanary").toInt(), 22);
3587 QVERIFY(!imageGuard.isNull()); // should still be alive.
3588 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3589 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3590 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3591 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3595 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3597 // sometimes reparenting can cause problems
3598 // (eg, if the ctxt is collected, varproperties are no longer available)
3599 // this test ensures that no crash occurs in that situation.
3600 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3601 QObject *object = component.create();
3602 QVERIFY(object != 0);
3603 QMetaObject::invokeMethod(object, "assignVarProp");
3604 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3605 QObject *rect = object->property("vp").value<QObject*>();
3606 QObject *text = rect->findChild<QObject*>("textOne");
3607 QObject *text2 = rect->findChild<QObject*>("textTwo");
3608 QWeakPointer<QObject> rectGuard(rect);
3609 QWeakPointer<QObject> textGuard(text);
3610 QWeakPointer<QObject> text2Guard(text2);
3611 QVERIFY(!rectGuard.isNull());
3612 QVERIFY(!textGuard.isNull());
3613 QVERIFY(!text2Guard.isNull());
3614 QCOMPARE(text->property("textCanary").toInt(), 11);
3615 QCOMPARE(text2->property("textCanary").toInt(), 12);
3616 // now construct an image which we will reparent.
3617 QMetaObject::invokeMethod(text2, "constructQObject");
3618 QObject *image = text2->property("vp").value<QObject*>();
3619 QWeakPointer<QObject> imageGuard(image);
3620 QVERIFY(!imageGuard.isNull());
3621 QCOMPARE(image->property("imageCanary").toInt(), 13);
3622 // now reparent the "Image" object (currently, it has JS ownership)
3623 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3624 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3625 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3626 QVERIFY(!imageGuard.isNull()); // should still be alive.
3627 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3629 QVERIFY(imageGuard.isNull()); // should now be dead.
3632 void tst_qdeclarativeecmascript::propertyVarCircular()
3634 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3635 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3636 QObject *object = component.create();
3637 QVERIFY(object != 0);
3638 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3639 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3640 QCOMPARE(object->property("canaryInt"), QVariant(5));
3641 QVariant canaryResourceVariant = object->property("canaryResource");
3642 QVERIFY(canaryResourceVariant.isValid());
3643 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3644 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3645 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3646 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3647 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3648 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3649 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3650 QCOMPARE(object->property("canaryInt"), QVariant(2));
3651 QCOMPARE(object->property("canaryResource"), QVariant(1));
3652 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3656 void tst_qdeclarativeecmascript::propertyVarCircular2()
3658 // track deletion of JS-owned parent item with Cpp-owned child
3659 // where the child has a var property referencing its parent.
3660 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3661 QObject *object = component.create();
3662 QVERIFY(object != 0);
3663 QMetaObject::invokeMethod(object, "assignCircular");
3664 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3665 QObject *rootObject = object->property("vp").value<QObject*>();
3666 QVERIFY(rootObject != 0);
3667 QObject *childObject = rootObject->findChild<QObject*>("text");
3668 QVERIFY(childObject != 0);
3669 QWeakPointer<QObject> rootObjectTracker(rootObject);
3670 QVERIFY(!rootObjectTracker.isNull());
3671 QWeakPointer<QObject> childObjectTracker(childObject);
3672 QVERIFY(!childObjectTracker.isNull());
3674 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3675 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3676 QMetaObject::invokeMethod(object, "deassignCircular");
3677 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3678 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3679 QVERIFY(childObjectTracker.isNull()); // should have been collected
3683 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3685 *(int*)(parameter) += 1;
3686 qPersistentDispose(object);
3689 void tst_qdeclarativeecmascript::propertyVarInheritance()
3691 int propertyVarWeakRefCallbackCount = 0;
3693 // enforce behaviour regarding element inheritance - ensure handle disposal.
3694 // The particular component under test here has a chain of references.
3695 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3696 QObject *object = component.create();
3697 QVERIFY(object != 0);
3698 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3699 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3700 // we want to be able to track when the varProperties array of the last metaobject is disposed
3701 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3702 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*>();
3703 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3704 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3705 v8::Persistent<v8::Value> icoCanaryHandle;
3706 v8::Persistent<v8::Value> ccoCanaryHandle;
3709 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3710 // public function which can return us a handle to something in the varProperties array.
3711 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3712 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3713 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3714 // as the varproperties array of each vmemo still references the resource.
3715 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3716 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3718 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3720 // now we deassign the var prop, which should trigger collection of item subtrees.
3721 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3722 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3723 // ensure that there are only weak handles to the underlying varProperties array remaining.
3725 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3727 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3728 // to what remains are weak, all varProperties arrays must have been collected.
3731 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3733 int propertyVarWeakRefCallbackCount = 0;
3735 // The particular component under test here does NOT have a chain of references; the
3736 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3737 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3738 QObject *object = component.create();
3739 QVERIFY(object != 0);
3740 QMetaObject::invokeMethod(object, "assignCircular");
3741 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3742 QObject *rootObject = object->property("vp").value<QObject*>();
3743 QVERIFY(rootObject != 0);
3744 QObject *childObject = rootObject->findChild<QObject*>("text");
3745 QVERIFY(childObject != 0);
3746 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3747 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3748 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3751 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3752 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3753 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3755 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3756 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3758 QMetaObject::invokeMethod(object, "deassignCircular");
3759 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3760 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3764 // Ensure that QObject type conversion works on binding assignment
3765 void tst_qdeclarativeecmascript::elementAssign()
3767 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3769 QObject *object = component.create();
3770 QVERIFY(object != 0);
3772 QCOMPARE(object->property("test").toBool(), true);
3778 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3780 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3782 QObject *object = component.create();
3783 QVERIFY(object != 0);
3785 QCOMPARE(object->property("test").toBool(), true);
3791 void tst_qdeclarativeecmascript::objectConversion()
3793 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3795 QObject *object = component.create();
3796 QVERIFY(object != 0);
3798 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3799 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3806 void tst_qdeclarativeecmascript::booleanConversion()
3808 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3810 QObject *object = component.create();
3811 QVERIFY(object != 0);
3813 QCOMPARE(object->property("test_true1").toBool(), true);
3814 QCOMPARE(object->property("test_true2").toBool(), true);
3815 QCOMPARE(object->property("test_true3").toBool(), true);
3816 QCOMPARE(object->property("test_true4").toBool(), true);
3817 QCOMPARE(object->property("test_true5").toBool(), true);
3819 QCOMPARE(object->property("test_false1").toBool(), false);
3820 QCOMPARE(object->property("test_false2").toBool(), false);
3821 QCOMPARE(object->property("test_false3").toBool(), false);
3826 void tst_qdeclarativeecmascript::handleReferenceManagement()
3831 // Linear QObject reference
3832 QDeclarativeEngine hrmEngine;
3833 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3834 QObject *object = component.create();
3835 QVERIFY(object != 0);
3836 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3837 cro->setDtorCount(&dtorCount);
3838 QMetaObject::invokeMethod(object, "createReference");
3840 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3842 hrmEngine.collectGarbage();
3843 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3844 QCOMPARE(dtorCount, 3);
3849 // Circular QObject reference
3850 QDeclarativeEngine hrmEngine;
3851 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3852 QObject *object = component.create();
3853 QVERIFY(object != 0);
3854 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3855 cro->setDtorCount(&dtorCount);
3856 QMetaObject::invokeMethod(object, "circularReference");
3858 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3860 hrmEngine.collectGarbage();
3861 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3862 QCOMPARE(dtorCount, 3);
3867 // Linear handle reference
3868 QDeclarativeEngine hrmEngine;
3869 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3870 QObject *object = component.create();
3871 QVERIFY(object != 0);
3872 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3874 crh->setDtorCount(&dtorCount);
3875 QMetaObject::invokeMethod(object, "createReference");
3876 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3877 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3878 QVERIFY(first != 0);
3879 QVERIFY(second != 0);
3880 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3881 // now we have to reparent second and make second owned by JS.
3882 second->setParent(0);
3883 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3885 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3887 hrmEngine.collectGarbage();
3888 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3889 QCOMPARE(dtorCount, 3);
3894 // Circular handle reference
3895 QDeclarativeEngine hrmEngine;
3896 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3897 QObject *object = component.create();
3898 QVERIFY(object != 0);
3899 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3901 crh->setDtorCount(&dtorCount);
3902 QMetaObject::invokeMethod(object, "circularReference");
3903 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3904 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3905 QVERIFY(first != 0);
3906 QVERIFY(second != 0);
3907 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3908 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3909 // now we have to reparent and change ownership.
3910 first->setParent(0);
3911 second->setParent(0);
3912 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3913 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3915 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3917 hrmEngine.collectGarbage();
3918 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3919 QCOMPARE(dtorCount, 3);
3924 // multiple engine interaction - linear reference
3925 QDeclarativeEngine hrmEngine1;
3926 QDeclarativeEngine hrmEngine2;
3927 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3928 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3929 QObject *object1 = component1.create();
3930 QObject *object2 = component2.create();
3931 QVERIFY(object1 != 0);
3932 QVERIFY(object2 != 0);
3933 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3934 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3937 crh1->setDtorCount(&dtorCount);
3938 crh2->setDtorCount(&dtorCount);
3939 QMetaObject::invokeMethod(object1, "createReference");
3940 QMetaObject::invokeMethod(object2, "createReference");
3941 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3942 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3943 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3944 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3945 QVERIFY(first1 != 0);
3946 QVERIFY(second1 != 0);
3947 QVERIFY(first2 != 0);
3948 QVERIFY(second2 != 0);
3949 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3950 // now we have to reparent second2 and make second2 owned by JS.
3951 second2->setParent(0);
3952 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3954 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3955 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3958 hrmEngine1.collectGarbage();
3959 hrmEngine2.collectGarbage();
3960 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3961 QCOMPARE(dtorCount, 6);
3966 // multiple engine interaction - circular reference
3967 QDeclarativeEngine hrmEngine1;
3968 QDeclarativeEngine hrmEngine2;
3969 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3970 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3971 QObject *object1 = component1.create();
3972 QObject *object2 = component2.create();
3973 QVERIFY(object1 != 0);
3974 QVERIFY(object2 != 0);
3975 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3976 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3979 crh1->setDtorCount(&dtorCount);
3980 crh2->setDtorCount(&dtorCount);
3981 QMetaObject::invokeMethod(object1, "createReference");
3982 QMetaObject::invokeMethod(object2, "createReference");
3983 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3984 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3985 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3986 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3987 QVERIFY(first1 != 0);
3988 QVERIFY(second1 != 0);
3989 QVERIFY(first2 != 0);
3990 QVERIFY(second2 != 0);
3991 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3992 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3993 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3994 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3995 // now we have to reparent and change ownership to JS.
3996 first1->setParent(0);
3997 second1->setParent(0);
3998 first2->setParent(0);
3999 second2->setParent(0);
4000 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4001 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4002 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4003 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4005 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4006 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4009 hrmEngine1.collectGarbage();
4010 hrmEngine2.collectGarbage();
4011 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4012 QCOMPARE(dtorCount, 6);
4017 // multiple engine interaction - linear reference with engine deletion
4018 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4019 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4020 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4021 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4022 QObject *object1 = component1.create();
4023 QObject *object2 = component2.create();
4024 QVERIFY(object1 != 0);
4025 QVERIFY(object2 != 0);
4026 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4027 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4030 crh1->setDtorCount(&dtorCount);
4031 crh2->setDtorCount(&dtorCount);
4032 QMetaObject::invokeMethod(object1, "createReference");
4033 QMetaObject::invokeMethod(object2, "createReference");
4034 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4035 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4036 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4037 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4038 QVERIFY(first1 != 0);
4039 QVERIFY(second1 != 0);
4040 QVERIFY(first2 != 0);
4041 QVERIFY(second2 != 0);
4042 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4043 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4044 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4045 // now we have to reparent and change ownership to JS.
4046 first1->setParent(crh1);
4047 second1->setParent(0);
4048 first2->setParent(0);
4049 second2->setParent(0);
4050 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4051 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4052 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4054 QCOMPARE(dtorCount, 0);
4057 QCOMPARE(dtorCount, 0);
4060 hrmEngine1->collectGarbage();
4061 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4062 QCOMPARE(dtorCount, 6);
4067 void tst_qdeclarativeecmascript::stringArg()
4069 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4070 QObject *object = component.create();
4071 QVERIFY(object != 0);
4072 QMetaObject::invokeMethod(object, "success");
4073 QVERIFY(object->property("returnValue").toBool());
4075 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4076 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4077 QMetaObject::invokeMethod(object, "failure");
4078 QVERIFY(object->property("returnValue").toBool());
4083 void tst_qdeclarativeecmascript::readonlyDeclaration()
4085 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4087 QObject *object = component.create();
4088 QVERIFY(object != 0);
4090 QCOMPARE(object->property("test").toBool(), true);
4095 Q_DECLARE_METATYPE(QList<int>)
4096 Q_DECLARE_METATYPE(QList<qreal>)
4097 Q_DECLARE_METATYPE(QList<bool>)
4098 Q_DECLARE_METATYPE(QList<QString>)
4099 Q_DECLARE_METATYPE(QList<QUrl>)
4100 void tst_qdeclarativeecmascript::sequenceConversionRead()
4103 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4104 QDeclarativeComponent component(&engine, qmlFile);
4105 QObject *object = component.create();
4106 QVERIFY(object != 0);
4107 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4110 QMetaObject::invokeMethod(object, "readSequences");
4111 QList<int> intList; intList << 1 << 2 << 3 << 4;
4112 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4113 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4114 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4115 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4116 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4117 QList<bool> boolList; boolList << true << false << true << false;
4118 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4119 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4120 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4121 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4122 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4123 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4124 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4125 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4126 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4127 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4128 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4130 QMetaObject::invokeMethod(object, "readSequenceElements");
4131 QCOMPARE(object->property("intVal").toInt(), 2);
4132 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4133 QCOMPARE(object->property("boolVal").toBool(), false);
4134 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4135 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4136 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4138 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4139 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4141 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4142 QDeclarativeProperty seqProp(seq, "intListProperty");
4143 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4144 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4145 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4147 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4148 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4154 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4155 QDeclarativeComponent component(&engine, qmlFile);
4156 QObject *object = component.create();
4157 QVERIFY(object != 0);
4158 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4161 // we haven't registered QList<QPoint> as a sequence type.
4162 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4163 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4164 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4165 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4167 QMetaObject::invokeMethod(object, "performTest");
4169 // QList<QPoint> has not been registered as a sequence type.
4170 QCOMPARE(object->property("pointListLength").toInt(), 0);
4171 QVERIFY(!object->property("pointList").isValid());
4172 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4173 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4174 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4180 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4183 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4184 QDeclarativeComponent component(&engine, qmlFile);
4185 QObject *object = component.create();
4186 QVERIFY(object != 0);
4187 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4190 QMetaObject::invokeMethod(object, "writeSequences");
4191 QCOMPARE(object->property("success").toBool(), true);
4193 QMetaObject::invokeMethod(object, "writeSequenceElements");
4194 QCOMPARE(object->property("success").toBool(), true);
4196 QMetaObject::invokeMethod(object, "writeOtherElements");
4197 QCOMPARE(object->property("success").toBool(), true);
4199 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4200 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4206 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4207 QDeclarativeComponent component(&engine, qmlFile);
4208 QObject *object = component.create();
4209 QVERIFY(object != 0);
4210 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4213 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4214 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4215 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4217 QMetaObject::invokeMethod(object, "performTest");
4219 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4220 QCOMPARE(seq->pointListProperty(), pointList);
4226 void tst_qdeclarativeecmascript::sequenceConversionArray()
4228 // ensure that in JS the returned sequences act just like normal JS Arrays.
4229 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4230 QDeclarativeComponent component(&engine, qmlFile);
4231 QObject *object = component.create();
4232 QVERIFY(object != 0);
4233 QMetaObject::invokeMethod(object, "indexedAccess");
4234 QVERIFY(object->property("success").toBool());
4235 QMetaObject::invokeMethod(object, "arrayOperations");
4236 QVERIFY(object->property("success").toBool());
4237 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4238 QVERIFY(object->property("success").toBool());
4239 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4240 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4244 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4246 // ensure that sequence conversion operations work correctly in a worker thread
4247 // and that serialisation between the main and worker thread succeeds.
4248 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4249 QDeclarativeComponent component(&engine, qmlFile);
4250 QObject *object = component.create();
4251 QVERIFY(object != 0);
4253 QMetaObject::invokeMethod(object, "testIntSequence");
4254 QTRY_VERIFY(object->property("finished").toBool());
4255 QVERIFY(object->property("success").toBool());
4257 QMetaObject::invokeMethod(object, "testQrealSequence");
4258 QTRY_VERIFY(object->property("finished").toBool());
4259 QVERIFY(object->property("success").toBool());
4261 QMetaObject::invokeMethod(object, "testBoolSequence");
4262 QTRY_VERIFY(object->property("finished").toBool());
4263 QVERIFY(object->property("success").toBool());
4265 QMetaObject::invokeMethod(object, "testStringSequence");
4266 QTRY_VERIFY(object->property("finished").toBool());
4267 QVERIFY(object->property("success").toBool());
4269 QMetaObject::invokeMethod(object, "testQStringSequence");
4270 QTRY_VERIFY(object->property("finished").toBool());
4271 QVERIFY(object->property("success").toBool());
4273 QMetaObject::invokeMethod(object, "testUrlSequence");
4274 QTRY_VERIFY(object->property("finished").toBool());
4275 QVERIFY(object->property("success").toBool());
4277 QMetaObject::invokeMethod(object, "testVariantSequence");
4278 QTRY_VERIFY(object->property("finished").toBool());
4279 QVERIFY(object->property("success").toBool());
4284 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4287 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4288 QDeclarativeComponent component(&engine, qmlFile);
4289 QObject *object = component.create();
4290 QVERIFY(object != 0);
4291 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4292 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4293 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4294 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4295 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4300 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4301 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4302 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4303 QDeclarativeComponent component(&engine, qmlFile);
4304 QObject *object = component.create();
4305 QVERIFY(object != 0);
4310 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4312 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4313 QDeclarativeComponent component(&engine, qmlFile);
4314 QObject *object = component.create();
4315 QVERIFY(object != 0);
4316 QMetaObject::invokeMethod(object, "testCopySequences");
4317 QCOMPARE(object->property("success").toBool(), true);
4318 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4319 QCOMPARE(object->property("success").toBool(), true);
4320 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4321 QCOMPARE(object->property("success").toBool(), true);
4325 void tst_qdeclarativeecmascript::assignSequenceTypes()
4327 // test binding array to sequence type property
4329 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.1.qml"));
4330 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4331 QVERIFY(object != 0);
4332 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4333 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4334 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4335 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4336 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4337 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4341 // test binding literal to sequence type property
4343 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.2.qml"));
4344 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4345 QVERIFY(object != 0);
4346 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4347 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4348 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4349 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4350 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4351 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4355 // test binding single value to sequence type property
4357 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.3.qml"));
4358 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4359 QVERIFY(object != 0);
4360 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4361 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4362 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4363 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4367 // test assigning array to sequence type property in js function
4369 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.4.qml"));
4370 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4371 QVERIFY(object != 0);
4372 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4373 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4374 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4375 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4376 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4377 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4381 // test assigning literal to sequence type property in js function
4383 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.5.qml"));
4384 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4385 QVERIFY(object != 0);
4386 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4387 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4388 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4389 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4390 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4391 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4395 // test assigning single value to sequence type property in js function
4397 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.6.qml"));
4398 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4399 QVERIFY(object != 0);
4400 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4401 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4402 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4403 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4408 // Test that assigning a null object works
4409 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4410 void tst_qdeclarativeecmascript::nullObjectBinding()
4412 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4414 QObject *object = component.create();
4415 QVERIFY(object != 0);
4417 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4422 // Test that bindings don't evaluate once the engine has been destroyed
4423 void tst_qdeclarativeecmascript::deletedEngine()
4425 QDeclarativeEngine *engine = new QDeclarativeEngine;
4426 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4428 QObject *object = component.create();
4429 QVERIFY(object != 0);
4431 QCOMPARE(object->property("a").toInt(), 39);
4432 object->setProperty("b", QVariant(9));
4433 QCOMPARE(object->property("a").toInt(), 117);
4437 QCOMPARE(object->property("a").toInt(), 117);
4438 object->setProperty("b", QVariant(10));
4439 QCOMPARE(object->property("a").toInt(), 117);
4444 // Test the crashing part of QTBUG-9705
4445 void tst_qdeclarativeecmascript::libraryScriptAssert()
4447 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4449 QObject *object = component.create();
4450 QVERIFY(object != 0);
4455 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4457 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4459 QObject *object = component.create();
4460 QVERIFY(object != 0);
4462 QCOMPARE(object->property("test1").toInt(), 10);
4463 QCOMPARE(object->property("test2").toInt(), 11);
4465 object->setProperty("runTest", true);
4467 QCOMPARE(object->property("test1"), QVariant());
4468 QCOMPARE(object->property("test2"), QVariant());
4474 void tst_qdeclarativeecmascript::qtbug_9792()
4476 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4478 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4480 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4481 QVERIFY(object != 0);
4483 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4484 object->basicSignal();
4488 transientErrorsMsgCount = 0;
4489 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4491 object->basicSignal();
4493 qInstallMsgHandler(old);
4495 QCOMPARE(transientErrorsMsgCount, 0);
4500 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4501 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4503 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4505 QObject *o = component.create();
4508 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4509 QVERIFY(nested != 0);
4511 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4514 nested = qvariant_cast<QObject *>(o->property("object"));
4515 QVERIFY(nested == 0);
4517 // If the bug is present, the next line will crash
4521 // Test that we shut down without stupid warnings
4522 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4525 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4527 QObject *o = component.create();
4529 transientErrorsMsgCount = 0;
4530 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4534 qInstallMsgHandler(old);
4536 QCOMPARE(transientErrorsMsgCount, 0);
4541 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4543 QObject *o = component.create();
4545 transientErrorsMsgCount = 0;
4546 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4550 qInstallMsgHandler(old);
4552 QCOMPARE(transientErrorsMsgCount, 0);
4556 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4559 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4561 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4564 QVERIFY(o->objectProperty() != 0);
4566 o->setProperty("runTest", true);
4568 QVERIFY(o->objectProperty() == 0);
4574 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4576 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4579 QVERIFY(o->objectProperty() == 0);
4585 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4587 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4589 QString url = component.url().toString();
4590 QString warning = url + ":4: Unable to assign a function to a property.";
4591 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4593 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4596 QVERIFY(!o->property("a").isValid());
4601 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4603 QFETCH(QString, triggerProperty);
4605 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4606 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4608 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4610 QVERIFY(!o->property("a").isValid());
4612 o->setProperty("aNumber", QVariant(5));
4613 o->setProperty(triggerProperty.toUtf8().constData(), true);
4614 QCOMPARE(o->property("a"), QVariant(50));
4616 o->setProperty("aNumber", QVariant(10));
4617 QCOMPARE(o->property("a"), QVariant(100));
4622 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4624 QTest::addColumn<QString>("triggerProperty");
4626 QTest::newRow("assign to property") << "assignToProperty";
4627 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4629 QTest::newRow("assign to value type") << "assignToValueType";
4631 QTest::newRow("use 'this'") << "assignWithThis";
4632 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4635 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4637 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4638 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4640 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4642 QVERIFY(!o->property("a").isValid());
4644 o->setProperty("assignFuncWithoutReturn", true);
4645 QVERIFY(!o->property("a").isValid());
4647 QString url = component.url().toString();
4648 QString warning = url + ":67: Unable to assign QString to int";
4649 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4650 o->setProperty("assignWrongType", true);
4652 warning = url + ":71: Unable to assign QString to int";
4653 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4654 o->setProperty("assignWrongTypeToValueType", true);
4659 void tst_qdeclarativeecmascript::eval()
4661 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4663 QObject *o = component.create();
4666 QCOMPARE(o->property("test1").toBool(), true);
4667 QCOMPARE(o->property("test2").toBool(), true);
4668 QCOMPARE(o->property("test3").toBool(), true);
4669 QCOMPARE(o->property("test4").toBool(), true);
4670 QCOMPARE(o->property("test5").toBool(), true);
4675 void tst_qdeclarativeecmascript::function()
4677 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4679 QObject *o = component.create();
4682 QCOMPARE(o->property("test1").toBool(), true);
4683 QCOMPARE(o->property("test2").toBool(), true);
4684 QCOMPARE(o->property("test3").toBool(), true);
4689 // Test the "Qt.include" method
4690 void tst_qdeclarativeecmascript::include()
4692 // Non-library relative include
4694 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4695 QObject *o = component.create();
4698 QCOMPARE(o->property("test0").toInt(), 99);
4699 QCOMPARE(o->property("test1").toBool(), true);
4700 QCOMPARE(o->property("test2").toBool(), true);
4701 QCOMPARE(o->property("test2_1").toBool(), true);
4702 QCOMPARE(o->property("test3").toBool(), true);
4703 QCOMPARE(o->property("test3_1").toBool(), true);
4708 // Library relative include
4710 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4711 QObject *o = component.create();
4714 QCOMPARE(o->property("test0").toInt(), 99);
4715 QCOMPARE(o->property("test1").toBool(), true);
4716 QCOMPARE(o->property("test2").toBool(), true);
4717 QCOMPARE(o->property("test2_1").toBool(), true);
4718 QCOMPARE(o->property("test3").toBool(), true);
4719 QCOMPARE(o->property("test3_1").toBool(), true);
4726 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4727 QObject *o = component.create();
4730 QCOMPARE(o->property("test1").toBool(), true);
4731 QCOMPARE(o->property("test2").toBool(), true);
4732 QCOMPARE(o->property("test3").toBool(), true);
4733 QCOMPARE(o->property("test4").toBool(), true);
4734 QCOMPARE(o->property("test5").toBool(), true);
4735 QCOMPARE(o->property("test6").toBool(), true);
4740 // Including file with ".pragma library"
4742 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4743 QObject *o = component.create();
4745 QCOMPARE(o->property("test1").toInt(), 100);
4752 TestHTTPServer server(8111);
4753 QVERIFY(server.isValid());
4754 server.serveDirectory(TESTDATA(""));
4756 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4757 QObject *o = component.create();
4760 QTRY_VERIFY(o->property("done").toBool() == true);
4761 QTRY_VERIFY(o->property("done2").toBool() == true);
4763 QCOMPARE(o->property("test1").toBool(), true);
4764 QCOMPARE(o->property("test2").toBool(), true);
4765 QCOMPARE(o->property("test3").toBool(), true);
4766 QCOMPARE(o->property("test4").toBool(), true);
4767 QCOMPARE(o->property("test5").toBool(), true);
4769 QCOMPARE(o->property("test6").toBool(), true);
4770 QCOMPARE(o->property("test7").toBool(), true);
4771 QCOMPARE(o->property("test8").toBool(), true);
4772 QCOMPARE(o->property("test9").toBool(), true);
4773 QCOMPARE(o->property("test10").toBool(), true);
4780 TestHTTPServer server(8111);
4781 QVERIFY(server.isValid());
4782 server.serveDirectory(TESTDATA(""));
4784 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4785 QObject *o = component.create();
4788 QTRY_VERIFY(o->property("done").toBool() == true);
4790 QCOMPARE(o->property("test1").toBool(), true);
4791 QCOMPARE(o->property("test2").toBool(), true);
4792 QCOMPARE(o->property("test3").toBool(), true);
4798 void tst_qdeclarativeecmascript::signalHandlers()
4800 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4801 QObject *o = component.create();
4804 QVERIFY(o->property("count").toInt() == 0);
4805 QMetaObject::invokeMethod(o, "testSignalCall");
4806 QCOMPARE(o->property("count").toInt(), 1);
4808 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4809 QCOMPARE(o->property("count").toInt(), 1);
4810 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4812 QVERIFY(o->property("funcCount").toInt() == 0);
4813 QMetaObject::invokeMethod(o, "testSignalConnection");
4814 QCOMPARE(o->property("funcCount").toInt(), 1);
4816 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4817 QCOMPARE(o->property("funcCount").toInt(), 2);
4819 QMetaObject::invokeMethod(o, "testSignalDefined");
4820 QCOMPARE(o->property("definedResult").toBool(), true);
4822 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4823 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4828 void tst_qdeclarativeecmascript::qtbug_10696()
4830 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4831 QObject *o = component.create();
4836 void tst_qdeclarativeecmascript::qtbug_11606()
4838 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4839 QObject *o = component.create();
4841 QCOMPARE(o->property("test").toBool(), true);
4845 void tst_qdeclarativeecmascript::qtbug_11600()
4847 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4848 QObject *o = component.create();
4850 QCOMPARE(o->property("test").toBool(), true);
4854 // Reading and writing non-scriptable properties should fail
4855 void tst_qdeclarativeecmascript::nonscriptable()
4857 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4858 QObject *o = component.create();
4860 QCOMPARE(o->property("readOk").toBool(), true);
4861 QCOMPARE(o->property("writeOk").toBool(), true);
4865 // deleteLater() should not be callable from QML
4866 void tst_qdeclarativeecmascript::deleteLater()
4868 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4869 QObject *o = component.create();
4871 QCOMPARE(o->property("test").toBool(), true);
4875 void tst_qdeclarativeecmascript::in()
4877 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4878 QObject *o = component.create();
4880 QCOMPARE(o->property("test1").toBool(), true);
4881 QCOMPARE(o->property("test2").toBool(), true);
4885 void tst_qdeclarativeecmascript::typeOf()
4887 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4888 QObject *o = component.create();
4890 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4891 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4892 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4893 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4894 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4895 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4896 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4897 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4898 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4899 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4904 void tst_qdeclarativeecmascript::sharedAttachedObject()
4906 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4907 QObject *o = component.create();
4909 QCOMPARE(o->property("test1").toBool(), true);
4910 QCOMPARE(o->property("test2").toBool(), true);
4915 void tst_qdeclarativeecmascript::objectName()
4917 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4918 QObject *o = component.create();
4921 QCOMPARE(o->property("test1").toString(), QString("hello"));
4922 QCOMPARE(o->property("test2").toString(), QString("ell"));
4924 o->setObjectName("world");
4926 QCOMPARE(o->property("test1").toString(), QString("world"));
4927 QCOMPARE(o->property("test2").toString(), QString("orl"));
4932 void tst_qdeclarativeecmascript::writeRemovesBinding()
4934 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4935 QObject *o = component.create();
4938 QCOMPARE(o->property("test").toBool(), true);
4943 // Test bindings assigned to alias properties actually assign to the alias' target
4944 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4946 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4947 QObject *o = component.create();
4950 QCOMPARE(o->property("test").toBool(), true);
4955 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4956 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4959 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4960 QObject *o = component.create();
4963 QCOMPARE(o->property("test").toBool(), true);
4969 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4970 QObject *o = component.create();
4973 QCOMPARE(o->property("test").toBool(), true);
4979 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4980 QObject *o = component.create();
4983 QCOMPARE(o->property("test").toBool(), true);
4989 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4990 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4993 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4994 QObject *o = component.create();
4997 QCOMPARE(o->property("test").toBool(), true);
5003 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
5004 QObject *o = component.create();
5007 QCOMPARE(o->property("test").toBool(), true);
5013 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
5014 QObject *o = component.create();
5017 QCOMPARE(o->property("test").toBool(), true);
5023 // Allow an alais to a composite element
5025 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5027 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
5029 QObject *object = component.create();
5030 QVERIFY(object != 0);
5035 void tst_qdeclarativeecmascript::qtbug_20344()
5037 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
5039 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5040 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5042 QObject *object = component.create();
5043 QVERIFY(object != 0);
5048 void tst_qdeclarativeecmascript::revisionErrors()
5051 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
5052 QString url = component.url().toString();
5054 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5055 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5056 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5058 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5059 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5060 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5061 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5062 QVERIFY(object != 0);
5066 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
5067 QString url = component.url().toString();
5069 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5070 // method2, prop2 from MyRevisionedClass not available
5071 // method4, prop4 from MyRevisionedSubclass not available
5072 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5073 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5074 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5075 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5076 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5078 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5079 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5080 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5081 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5082 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5083 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5084 QVERIFY(object != 0);
5088 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5089 QString url = component.url().toString();
5091 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5092 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5093 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5094 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5095 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5096 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5097 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5098 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5099 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5100 QVERIFY(object != 0);
5105 void tst_qdeclarativeecmascript::revision()
5108 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5109 QString url = component.url().toString();
5111 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5112 QVERIFY(object != 0);
5116 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5117 QString url = component.url().toString();
5119 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5120 QVERIFY(object != 0);
5124 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5125 QString url = component.url().toString();
5127 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5128 QVERIFY(object != 0);
5131 // Test that non-root classes can resolve revisioned methods
5133 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5135 QObject *object = component.create();
5136 QVERIFY(object != 0);
5137 QCOMPARE(object->property("test").toReal(), 11.);
5142 void tst_qdeclarativeecmascript::realToInt()
5144 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5145 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5146 QVERIFY(object != 0);
5148 QMetaObject::invokeMethod(object, "test1");
5149 QCOMPARE(object->value(), int(4));
5150 QMetaObject::invokeMethod(object, "test2");
5151 QCOMPARE(object->value(), int(8));
5153 void tst_qdeclarativeecmascript::dynamicString()
5155 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5156 QObject *object = component.create();
5157 QVERIFY(object != 0);
5158 QCOMPARE(object->property("stringProperty").toString(),
5159 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5162 void tst_qdeclarativeecmascript::automaticSemicolon()
5164 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5165 QObject *object = component.create();
5166 QVERIFY(object != 0);
5169 void tst_qdeclarativeecmascript::unaryExpression()
5171 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5172 QObject *object = component.create();
5173 QVERIFY(object != 0);
5176 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5177 void tst_qdeclarativeecmascript::doubleEvaluate()
5179 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5180 QObject *object = component.create();
5181 QVERIFY(object != 0);
5182 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5184 QCOMPARE(wc->count(), 1);
5186 wc->setProperty("x", 9);
5188 QCOMPARE(wc->count(), 2);
5193 static QStringList messages;
5194 static void captureMsgHandler(QtMsgType, const char *msg)
5196 messages.append(QLatin1String(msg));
5199 void tst_qdeclarativeecmascript::nonNotifyable()
5201 QV4Compiler::enableV4(false);
5202 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5203 QV4Compiler::enableV4(true);
5205 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5207 QObject *object = component.create();
5208 qInstallMsgHandler(old);
5210 QVERIFY(object != 0);
5212 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5213 component.url().toString() +
5214 QLatin1String(":5 depends on non-NOTIFYable properties:");
5215 QString expected2 = QLatin1String(" ") +
5216 QLatin1String(object->metaObject()->className()) +
5217 QLatin1String("::value");
5219 QCOMPARE(messages.length(), 2);
5220 QCOMPARE(messages.at(0), expected1);
5221 QCOMPARE(messages.at(1), expected2);
5226 void tst_qdeclarativeecmascript::forInLoop()
5228 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5229 QObject *object = component.create();
5230 QVERIFY(object != 0);
5232 QMetaObject::invokeMethod(object, "listProperty");
5234 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5235 QCOMPARE(r.size(), 3);
5236 QCOMPARE(r[0],QLatin1String("0=obj1"));
5237 QCOMPARE(r[1],QLatin1String("1=obj2"));
5238 QCOMPARE(r[2],QLatin1String("2=obj3"));
5240 //TODO: should test for in loop for other objects (such as QObjects) as well.
5245 // An object the binding depends on is deleted while the binding is still running
5246 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5248 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5249 QObject *object = component.create();
5250 QVERIFY(object != 0);
5254 void tst_qdeclarativeecmascript::qtbug_22679()
5257 object.setStringProperty(QLatin1String("Please work correctly"));
5258 engine.rootContext()->setContextProperty("contextProp", &object);
5260 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5261 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5262 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5264 QObject *o = component.create();
5266 QCOMPARE(warningsSpy.count(), 0);
5270 void tst_qdeclarativeecmascript::qtbug_22843_data()
5272 QTest::addColumn<bool>("library");
5274 QTest::newRow("without .pragma library") << false;
5275 QTest::newRow("with .pragma library") << true;
5278 void tst_qdeclarativeecmascript::qtbug_22843()
5280 QFETCH(bool, library);
5282 QString fileName("qtbug_22843");
5284 fileName += QLatin1String(".library");
5285 fileName += QLatin1String(".qml");
5287 QDeclarativeComponent component(&engine, TEST_FILE(fileName));
5288 QString url = component.url().toString();
5289 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5290 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5292 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5293 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5294 for (int x = 0; x < 3; ++x) {
5295 warningsSpy.clear();
5296 // For libraries, only the first import attempt should produce a
5297 // SyntaxError warning; subsequent component creation should not
5298 // attempt to reload the script.
5299 bool expectSyntaxError = !library || (x == 0);
5300 if (expectSyntaxError)
5301 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5302 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5303 QObject *object = component.create();
5304 QVERIFY(object != 0);
5305 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5311 void tst_qdeclarativeecmascript::switchStatement()
5314 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.1.qml"));
5315 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5316 QVERIFY(object != 0);
5318 // `object->value()' is the number of executed statements
5320 object->setStringProperty("A");
5321 QCOMPARE(object->value(), 5);
5323 object->setStringProperty("S");
5324 QCOMPARE(object->value(), 3);
5326 object->setStringProperty("D");
5327 QCOMPARE(object->value(), 3);
5329 object->setStringProperty("F");
5330 QCOMPARE(object->value(), 4);
5332 object->setStringProperty("something else");
5333 QCOMPARE(object->value(), 1);
5337 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.2.qml"));
5338 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5339 QVERIFY(object != 0);
5341 // `object->value()' is the number of executed statements
5343 object->setStringProperty("A");
5344 QCOMPARE(object->value(), 5);
5346 object->setStringProperty("S");
5347 QCOMPARE(object->value(), 3);
5349 object->setStringProperty("D");
5350 QCOMPARE(object->value(), 3);
5352 object->setStringProperty("F");
5353 QCOMPARE(object->value(), 3);
5355 object->setStringProperty("something else");
5356 QCOMPARE(object->value(), 4);
5360 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.3.qml"));
5361 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5362 QVERIFY(object != 0);
5364 // `object->value()' is the number of executed statements
5366 object->setStringProperty("A");
5367 QCOMPARE(object->value(), 5);
5369 object->setStringProperty("S");
5370 QCOMPARE(object->value(), 3);
5372 object->setStringProperty("D");
5373 QCOMPARE(object->value(), 3);
5375 object->setStringProperty("F");
5376 QCOMPARE(object->value(), 3);
5378 object->setStringProperty("something else");
5379 QCOMPARE(object->value(), 6);
5383 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.4.qml"));
5384 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5385 QVERIFY(object != 0);
5387 // `object->value()' is the number of executed statements
5389 object->setStringProperty("A");
5390 QCOMPARE(object->value(), 5);
5392 object->setStringProperty("S");
5393 QCOMPARE(object->value(), 3);
5395 object->setStringProperty("D");
5396 QCOMPARE(object->value(), 3);
5398 object->setStringProperty("F");
5399 QCOMPARE(object->value(), 3);
5401 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5402 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5404 object->setStringProperty("something else");
5408 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.5.qml"));
5409 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5410 QVERIFY(object != 0);
5412 // `object->value()' is the number of executed statements
5414 object->setStringProperty("A");
5415 QCOMPARE(object->value(), 1);
5417 object->setStringProperty("S");
5418 QCOMPARE(object->value(), 1);
5420 object->setStringProperty("D");
5421 QCOMPARE(object->value(), 1);
5423 object->setStringProperty("F");
5424 QCOMPARE(object->value(), 1);
5426 object->setStringProperty("something else");
5427 QCOMPARE(object->value(), 1);
5431 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.6.qml"));
5432 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5433 QVERIFY(object != 0);
5435 // `object->value()' is the number of executed statements
5437 object->setStringProperty("A");
5438 QCOMPARE(object->value(), 123);
5440 object->setStringProperty("S");
5441 QCOMPARE(object->value(), 123);
5443 object->setStringProperty("D");
5444 QCOMPARE(object->value(), 321);
5446 object->setStringProperty("F");
5447 QCOMPARE(object->value(), 321);
5449 object->setStringProperty("something else");
5450 QCOMPARE(object->value(), 0);
5454 void tst_qdeclarativeecmascript::withStatement()
5457 QDeclarativeComponent component(&engine, TEST_FILE("withStatement.1.qml"));
5458 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5459 QVERIFY(object != 0);
5461 QCOMPARE(object->value(), 123);
5465 void tst_qdeclarativeecmascript::tryStatement()
5468 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.1.qml"));
5469 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5470 QVERIFY(object != 0);
5472 QCOMPARE(object->value(), 123);
5476 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.2.qml"));
5477 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5478 QVERIFY(object != 0);
5480 QCOMPARE(object->value(), 321);
5484 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.3.qml"));
5485 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5486 QVERIFY(object != 0);
5488 QCOMPARE(object->value(), 1);
5492 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.4.qml"));
5493 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5494 QVERIFY(object != 0);
5496 QCOMPARE(object->value(), 1);
5500 QTEST_MAIN(tst_qdeclarativeecmascript)
5502 #include "tst_qdeclarativeecmascript.moc"