1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include <private/qdeclarativevmemetaobject_p.h>
53 #include <private/qv4compiler_p.h>
54 #include "testtypes.h"
55 #include "testhttpserver.h"
56 #include "../../shared/util.h"
59 This test covers evaluation of ECMAScript expressions and bindings from within
60 QML. This does not include static QML language issues.
62 Static QML language issues are covered in qmllanguage
65 class tst_qdeclarativeecmascript : public QDeclarativeDataTest
69 tst_qdeclarativeecmascript() {}
73 void assignBasicTypes();
74 void idShortcutInvalidates();
75 void boolPropertiesEvaluateAsBool();
77 void signalAssignment();
79 void basicExpressions();
80 void basicExpressions_data();
81 void arrayExpressions();
82 void contextPropertiesTriggerReeval();
83 void objectPropertiesTriggerReeval();
84 void deferredProperties();
85 void deferredPropertiesErrors();
86 void extensionObjects();
87 void overrideExtensionProperties();
88 void attachedProperties();
90 void valueTypeFunctions();
91 void constantsOverrideBindings();
92 void outerBindingOverridesInnerBinding();
93 void aliasPropertyAndBinding();
94 void aliasPropertyReset();
95 void nonExistentAttachedObject();
98 void signalParameterTypes();
99 void objectsCompareAsEqual();
100 void dynamicCreation_data();
101 void dynamicCreation();
102 void dynamicDestruction();
103 void objectToString();
104 void objectHasOwnProperty();
105 void selfDeletingBinding();
106 void extendedObjectPropertyLookup();
107 void extendedObjectPropertyLookup2();
109 void functionErrors();
110 void propertyAssignmentErrors();
111 void signalTriggeredBindings();
112 void listProperties();
113 void exceptionClearsOnReeval();
114 void exceptionSlotProducesWarning();
115 void exceptionBindingProducesWarning();
116 void compileInvalidBinding();
117 void transientErrors();
118 void shutdownErrors();
119 void compositePropertyType();
121 void undefinedResetsProperty();
122 void listToVariant();
123 void listAssignment();
124 void multiEngineObject();
125 void deletedObject();
126 void attachedPropertyScope();
127 void scriptConnect();
128 void scriptDisconnect();
130 void cppOwnershipReturnValue();
131 void ownershipCustomReturnValue();
132 void qlistqobjectMethods();
133 void strictlyEquals();
135 void numberAssignment();
136 void propertySplicing();
137 void signalWithUnknownTypes();
138 void signalWithJSValueInVariant_data();
139 void signalWithJSValueInVariant();
140 void signalWithJSValueInVariant_twoEngines_data();
141 void signalWithJSValueInVariant_twoEngines();
142 void signalWithQJSValue_data();
143 void signalWithQJSValue();
144 void moduleApi_data();
146 void importScripts_data();
147 void importScripts();
148 void scarceResources();
149 void scarceResources_data();
150 void scarceResources_other();
151 void propertyChangeSlots();
152 void propertyVar_data();
154 void propertyVarCpp();
155 void propertyVarOwnership();
156 void propertyVarImplicitOwnership();
157 void propertyVarReparent();
158 void propertyVarReparentNullContext();
159 void propertyVarCircular();
160 void propertyVarCircular2();
161 void propertyVarInheritance();
162 void propertyVarInheritance2();
163 void elementAssign();
164 void objectPassThroughSignals();
165 void objectConversion();
166 void booleanConversion();
167 void handleReferenceManagement();
169 void readonlyDeclaration();
170 void sequenceConversionRead();
171 void sequenceConversionWrite();
172 void sequenceConversionArray();
173 void sequenceConversionIndexes();
174 void sequenceConversionThreads();
175 void sequenceConversionBindings();
176 void sequenceConversionCopy();
177 void assignSequenceTypes();
183 void dynamicCreationCrash();
184 void dynamicCreationOwnership();
186 void nullObjectBinding();
187 void deletedEngine();
188 void libraryScriptAssert();
189 void variantsAssignedUndefined();
191 void qtcreatorbug_1289();
192 void noSpuriousWarningsAtShutdown();
193 void canAssignNullToQObject();
194 void functionAssignment_fromBinding();
195 void functionAssignment_fromJS();
196 void functionAssignment_fromJS_data();
197 void functionAssignmentfromJS_invalid();
200 void functionException();
205 void qobjectConnectionListExceptionHandling();
206 void nonscriptable();
210 void sharedAttachedObject();
212 void writeRemovesBinding();
213 void aliasBindingsAssignCorrectly();
214 void aliasBindingsOverrideTarget();
215 void aliasWritesOverrideBindings();
216 void aliasToCompositeElement();
219 void urlPropertyWithEncoding();
220 void urlListPropertyWithEncoding();
221 void dynamicString();
223 void signalHandlers();
224 void doubleEvaluate();
226 void nonNotifyable();
227 void deleteWhileBindingRunning();
228 void callQtInvokables();
229 void invokableObjectArg();
230 void invokableObjectRet();
233 void qtbug_22843_data();
235 void rewriteMultiLineStrings();
236 void revisionErrors();
239 void automaticSemicolon();
240 void unaryExpression();
241 void switchStatement();
242 void withStatement();
246 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
247 QDeclarativeEngine engine;
250 void tst_qdeclarativeecmascript::initTestCase()
252 QDeclarativeDataTest::initTestCase();
256 void tst_qdeclarativeecmascript::assignBasicTypes()
259 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
260 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
261 QVERIFY(object != 0);
262 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
263 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
264 QCOMPARE(object->stringProperty(), QString("Hello World!"));
265 QCOMPARE(object->uintProperty(), uint(10));
266 QCOMPARE(object->intProperty(), -19);
267 QCOMPARE((float)object->realProperty(), float(23.2));
268 QCOMPARE((float)object->doubleProperty(), float(-19.75));
269 QCOMPARE((float)object->floatProperty(), float(8.5));
270 QCOMPARE(object->colorProperty(), QColor("red"));
271 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
272 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
273 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
274 QCOMPARE(object->pointProperty(), QPoint(99,13));
275 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
276 QCOMPARE(object->sizeProperty(), QSize(99, 13));
277 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
278 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
279 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
280 QCOMPARE(object->boolProperty(), true);
281 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
282 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
283 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
287 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
288 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
289 QVERIFY(object != 0);
290 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
291 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
292 QCOMPARE(object->stringProperty(), QString("Hello World!"));
293 QCOMPARE(object->uintProperty(), uint(10));
294 QCOMPARE(object->intProperty(), -19);
295 QCOMPARE((float)object->realProperty(), float(23.2));
296 QCOMPARE((float)object->doubleProperty(), float(-19.75));
297 QCOMPARE((float)object->floatProperty(), float(8.5));
298 QCOMPARE(object->colorProperty(), QColor("red"));
299 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
300 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
301 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
302 QCOMPARE(object->pointProperty(), QPoint(99,13));
303 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
304 QCOMPARE(object->sizeProperty(), QSize(99, 13));
305 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
306 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
307 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
308 QCOMPARE(object->boolProperty(), true);
309 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
310 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
311 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
316 void tst_qdeclarativeecmascript::idShortcutInvalidates()
319 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
320 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
321 QVERIFY(object != 0);
322 QVERIFY(object->objectProperty() != 0);
323 delete object->objectProperty();
324 QVERIFY(object->objectProperty() == 0);
329 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
330 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
331 QVERIFY(object != 0);
332 QVERIFY(object->objectProperty() != 0);
333 delete object->objectProperty();
334 QVERIFY(object->objectProperty() == 0);
339 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
342 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
343 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
344 QVERIFY(object != 0);
345 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
349 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
350 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
351 QVERIFY(object != 0);
352 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
357 void tst_qdeclarativeecmascript::signalAssignment()
360 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
361 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
362 QVERIFY(object != 0);
363 QCOMPARE(object->string(), QString());
364 emit object->basicSignal();
365 QCOMPARE(object->string(), QString("pass"));
370 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
371 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
372 QVERIFY(object != 0);
373 QCOMPARE(object->string(), QString());
374 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
375 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
380 void tst_qdeclarativeecmascript::methods()
383 QDeclarativeComponent component(&engine, testFileUrl("methods.1.qml"));
384 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
385 QVERIFY(object != 0);
386 QCOMPARE(object->methodCalled(), false);
387 QCOMPARE(object->methodIntCalled(), false);
388 emit object->basicSignal();
389 QCOMPARE(object->methodCalled(), true);
390 QCOMPARE(object->methodIntCalled(), false);
395 QDeclarativeComponent component(&engine, testFileUrl("methods.2.qml"));
396 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
397 QVERIFY(object != 0);
398 QCOMPARE(object->methodCalled(), false);
399 QCOMPARE(object->methodIntCalled(), false);
400 emit object->basicSignal();
401 QCOMPARE(object->methodCalled(), false);
402 QCOMPARE(object->methodIntCalled(), true);
407 QDeclarativeComponent component(&engine, testFileUrl("methods.3.qml"));
408 QObject *object = component.create();
409 QVERIFY(object != 0);
410 QCOMPARE(object->property("test").toInt(), 19);
415 QDeclarativeComponent component(&engine, testFileUrl("methods.4.qml"));
416 QObject *object = component.create();
417 QVERIFY(object != 0);
418 QCOMPARE(object->property("test").toInt(), 19);
419 QCOMPARE(object->property("test2").toInt(), 17);
420 QCOMPARE(object->property("test3").toInt(), 16);
425 QDeclarativeComponent component(&engine, testFileUrl("methods.5.qml"));
426 QObject *object = component.create();
427 QVERIFY(object != 0);
428 QCOMPARE(object->property("test").toInt(), 9);
433 void tst_qdeclarativeecmascript::bindingLoop()
435 QDeclarativeComponent component(&engine, testFileUrl("bindingLoop.qml"));
436 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
437 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
438 QObject *object = component.create();
439 QVERIFY(object != 0);
443 void tst_qdeclarativeecmascript::basicExpressions_data()
445 QTest::addColumn<QString>("expression");
446 QTest::addColumn<QVariant>("result");
447 QTest::addColumn<bool>("nest");
449 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
450 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
451 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
452 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
453 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
454 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
455 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
456 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
457 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
458 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
459 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
460 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
461 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
462 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
463 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
464 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
465 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
466 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
467 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
470 void tst_qdeclarativeecmascript::basicExpressions()
472 QFETCH(QString, expression);
473 QFETCH(QVariant, result);
479 MyDefaultObject1 default1;
480 MyDefaultObject3 default3;
481 object1.setStringProperty("Object1");
482 object2.setStringProperty("Object2");
483 object3.setStringProperty("Object3");
485 QDeclarativeContext context(engine.rootContext());
486 QDeclarativeContext nestedContext(&context);
488 context.setContextObject(&default1);
489 context.setContextProperty("a", QVariant(1944));
490 context.setContextProperty("b", QVariant("Milk"));
491 context.setContextProperty("object", &object1);
492 context.setContextProperty("objectOverride", &object2);
493 nestedContext.setContextObject(&default3);
494 nestedContext.setContextProperty("b", QVariant("Cow"));
495 nestedContext.setContextProperty("objectOverride", &object3);
496 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
498 MyExpression expr(nest?&nestedContext:&context, expression);
499 QCOMPARE(expr.evaluate(), result);
502 void tst_qdeclarativeecmascript::arrayExpressions()
508 QDeclarativeContext context(engine.rootContext());
509 context.setContextProperty("a", &obj1);
510 context.setContextProperty("b", &obj2);
511 context.setContextProperty("c", &obj3);
513 MyExpression expr(&context, "[a, b, c, 10]");
514 QVariant result = expr.evaluate();
515 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
516 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
517 QCOMPARE(list.count(), 4);
518 QCOMPARE(list.at(0), &obj1);
519 QCOMPARE(list.at(1), &obj2);
520 QCOMPARE(list.at(2), &obj3);
521 QCOMPARE(list.at(3), (QObject *)0);
524 // Tests that modifying a context property will reevaluate expressions
525 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
527 QDeclarativeContext context(engine.rootContext());
530 MyQmlObject *object3 = new MyQmlObject;
532 object1.setStringProperty("Hello");
533 object2.setStringProperty("World");
535 context.setContextProperty("testProp", QVariant(1));
536 context.setContextProperty("testObj", &object1);
537 context.setContextProperty("testObj2", object3);
540 MyExpression expr(&context, "testProp + 1");
541 QCOMPARE(expr.changed, false);
542 QCOMPARE(expr.evaluate(), QVariant(2));
544 context.setContextProperty("testProp", QVariant(2));
545 QCOMPARE(expr.changed, true);
546 QCOMPARE(expr.evaluate(), QVariant(3));
550 MyExpression expr(&context, "testProp + testProp + testProp");
551 QCOMPARE(expr.changed, false);
552 QCOMPARE(expr.evaluate(), QVariant(6));
554 context.setContextProperty("testProp", QVariant(4));
555 QCOMPARE(expr.changed, true);
556 QCOMPARE(expr.evaluate(), QVariant(12));
560 MyExpression expr(&context, "testObj.stringProperty");
561 QCOMPARE(expr.changed, false);
562 QCOMPARE(expr.evaluate(), QVariant("Hello"));
564 context.setContextProperty("testObj", &object2);
565 QCOMPARE(expr.changed, true);
566 QCOMPARE(expr.evaluate(), QVariant("World"));
570 MyExpression expr(&context, "testObj.stringProperty /**/");
571 QCOMPARE(expr.changed, false);
572 QCOMPARE(expr.evaluate(), QVariant("World"));
574 context.setContextProperty("testObj", &object1);
575 QCOMPARE(expr.changed, true);
576 QCOMPARE(expr.evaluate(), QVariant("Hello"));
580 MyExpression expr(&context, "testObj2");
581 QCOMPARE(expr.changed, false);
582 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
588 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
590 QDeclarativeContext context(engine.rootContext());
594 context.setContextProperty("testObj", &object1);
596 object1.setStringProperty(QLatin1String("Hello"));
597 object2.setStringProperty(QLatin1String("Dog"));
598 object3.setStringProperty(QLatin1String("Cat"));
601 MyExpression expr(&context, "testObj.stringProperty");
602 QCOMPARE(expr.changed, false);
603 QCOMPARE(expr.evaluate(), QVariant("Hello"));
605 object1.setStringProperty(QLatin1String("World"));
606 QCOMPARE(expr.changed, true);
607 QCOMPARE(expr.evaluate(), QVariant("World"));
611 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
612 QCOMPARE(expr.changed, false);
613 QCOMPARE(expr.evaluate(), QVariant());
615 object1.setObjectProperty(&object2);
616 QCOMPARE(expr.changed, true);
617 expr.changed = false;
618 QCOMPARE(expr.evaluate(), QVariant("Dog"));
620 object1.setObjectProperty(&object3);
621 QCOMPARE(expr.changed, true);
622 expr.changed = false;
623 QCOMPARE(expr.evaluate(), QVariant("Cat"));
625 object1.setObjectProperty(0);
626 QCOMPARE(expr.changed, true);
627 expr.changed = false;
628 QCOMPARE(expr.evaluate(), QVariant());
630 object1.setObjectProperty(&object3);
631 QCOMPARE(expr.changed, true);
632 expr.changed = false;
633 QCOMPARE(expr.evaluate(), QVariant("Cat"));
635 object3.setStringProperty("Donkey");
636 QCOMPARE(expr.changed, true);
637 expr.changed = false;
638 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
642 void tst_qdeclarativeecmascript::deferredProperties()
644 QDeclarativeComponent component(&engine, testFileUrl("deferredProperties.qml"));
645 MyDeferredObject *object =
646 qobject_cast<MyDeferredObject *>(component.create());
647 QVERIFY(object != 0);
648 QCOMPARE(object->value(), 0);
649 QVERIFY(object->objectProperty() == 0);
650 QVERIFY(object->objectProperty2() != 0);
651 qmlExecuteDeferred(object);
652 QCOMPARE(object->value(), 10);
653 QVERIFY(object->objectProperty() != 0);
654 MyQmlObject *qmlObject =
655 qobject_cast<MyQmlObject *>(object->objectProperty());
656 QVERIFY(qmlObject != 0);
657 QCOMPARE(qmlObject->value(), 10);
658 object->setValue(19);
659 QCOMPARE(qmlObject->value(), 19);
664 // Check errors on deferred properties are correctly emitted
665 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
667 QDeclarativeComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
668 MyDeferredObject *object =
669 qobject_cast<MyDeferredObject *>(component.create());
670 QVERIFY(object != 0);
671 QCOMPARE(object->value(), 0);
672 QVERIFY(object->objectProperty() == 0);
673 QVERIFY(object->objectProperty2() == 0);
675 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
676 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
678 qmlExecuteDeferred(object);
683 void tst_qdeclarativeecmascript::extensionObjects()
685 QDeclarativeComponent component(&engine, testFileUrl("extensionObjects.qml"));
686 MyExtendedObject *object =
687 qobject_cast<MyExtendedObject *>(component.create());
688 QVERIFY(object != 0);
689 QCOMPARE(object->baseProperty(), 13);
690 QCOMPARE(object->coreProperty(), 9);
691 object->setProperty("extendedProperty", QVariant(11));
692 object->setProperty("baseExtendedProperty", QVariant(92));
693 QCOMPARE(object->coreProperty(), 11);
694 QCOMPARE(object->baseProperty(), 92);
696 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
698 QCOMPARE(nested->baseProperty(), 13);
699 QCOMPARE(nested->coreProperty(), 9);
700 nested->setProperty("extendedProperty", QVariant(11));
701 nested->setProperty("baseExtendedProperty", QVariant(92));
702 QCOMPARE(nested->coreProperty(), 11);
703 QCOMPARE(nested->baseProperty(), 92);
708 void tst_qdeclarativeecmascript::overrideExtensionProperties()
710 QDeclarativeComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
711 OverrideDefaultPropertyObject *object =
712 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
713 QVERIFY(object != 0);
714 QVERIFY(object->secondProperty() != 0);
715 QVERIFY(object->firstProperty() == 0);
720 void tst_qdeclarativeecmascript::attachedProperties()
723 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.qml"));
724 QObject *object = component.create();
725 QVERIFY(object != 0);
726 QCOMPARE(object->property("a").toInt(), 19);
727 QCOMPARE(object->property("b").toInt(), 19);
728 QCOMPARE(object->property("c").toInt(), 19);
729 QCOMPARE(object->property("d").toInt(), 19);
734 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
735 QObject *object = component.create();
736 QVERIFY(object != 0);
737 QCOMPARE(object->property("a").toInt(), 26);
738 QCOMPARE(object->property("b").toInt(), 26);
739 QCOMPARE(object->property("c").toInt(), 26);
740 QCOMPARE(object->property("d").toInt(), 26);
746 QDeclarativeComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
747 QObject *object = component.create();
748 QVERIFY(object != 0);
750 QMetaObject::invokeMethod(object, "writeValue2");
752 MyQmlAttachedObject *attached =
753 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
754 QVERIFY(attached != 0);
756 QCOMPARE(attached->value2(), 9);
761 void tst_qdeclarativeecmascript::enums()
765 QDeclarativeComponent component(&engine, testFileUrl("enums.1.qml"));
766 QObject *object = component.create();
767 QVERIFY(object != 0);
769 QCOMPARE(object->property("a").toInt(), 0);
770 QCOMPARE(object->property("b").toInt(), 1);
771 QCOMPARE(object->property("c").toInt(), 2);
772 QCOMPARE(object->property("d").toInt(), 3);
773 QCOMPARE(object->property("e").toInt(), 0);
774 QCOMPARE(object->property("f").toInt(), 1);
775 QCOMPARE(object->property("g").toInt(), 2);
776 QCOMPARE(object->property("h").toInt(), 3);
777 QCOMPARE(object->property("i").toInt(), 19);
778 QCOMPARE(object->property("j").toInt(), 19);
782 // Non-existent enums
784 QDeclarativeComponent component(&engine, testFileUrl("enums.2.qml"));
786 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
787 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
788 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
789 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
791 QObject *object = component.create();
792 QVERIFY(object != 0);
793 QCOMPARE(object->property("a").toInt(), 0);
794 QCOMPARE(object->property("b").toInt(), 0);
800 void tst_qdeclarativeecmascript::valueTypeFunctions()
802 QDeclarativeComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
803 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
805 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
806 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
812 Tests that writing a constant to a property with a binding on it disables the
815 void tst_qdeclarativeecmascript::constantsOverrideBindings()
819 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
820 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
821 QVERIFY(object != 0);
823 QCOMPARE(object->property("c2").toInt(), 0);
824 object->setProperty("c1", QVariant(9));
825 QCOMPARE(object->property("c2").toInt(), 9);
827 emit object->basicSignal();
829 QCOMPARE(object->property("c2").toInt(), 13);
830 object->setProperty("c1", QVariant(8));
831 QCOMPARE(object->property("c2").toInt(), 13);
836 // During construction
838 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
839 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
840 QVERIFY(object != 0);
842 QCOMPARE(object->property("c1").toInt(), 0);
843 QCOMPARE(object->property("c2").toInt(), 10);
844 object->setProperty("c1", QVariant(9));
845 QCOMPARE(object->property("c1").toInt(), 9);
846 QCOMPARE(object->property("c2").toInt(), 10);
854 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.3.qml"));
855 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
856 QVERIFY(object != 0);
858 QCOMPARE(object->property("c2").toInt(), 0);
859 object->setProperty("c1", QVariant(9));
860 QCOMPARE(object->property("c2").toInt(), 9);
862 object->setProperty("c2", QVariant(13));
863 QCOMPARE(object->property("c2").toInt(), 13);
864 object->setProperty("c1", QVariant(7));
865 QCOMPARE(object->property("c1").toInt(), 7);
866 QCOMPARE(object->property("c2").toInt(), 13);
874 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
875 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
876 QVERIFY(object != 0);
878 QCOMPARE(object->property("c1").toInt(), 0);
879 QCOMPARE(object->property("c3").toInt(), 10);
880 object->setProperty("c1", QVariant(9));
881 QCOMPARE(object->property("c1").toInt(), 9);
882 QCOMPARE(object->property("c3").toInt(), 10);
889 Tests that assigning a binding to a property that already has a binding causes
890 the original binding to be disabled.
892 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
894 QDeclarativeComponent component(&engine,
895 testFileUrl("outerBindingOverridesInnerBinding.qml"));
896 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
897 QVERIFY(object != 0);
899 QCOMPARE(object->property("c1").toInt(), 0);
900 QCOMPARE(object->property("c2").toInt(), 0);
901 QCOMPARE(object->property("c3").toInt(), 0);
903 object->setProperty("c1", QVariant(9));
904 QCOMPARE(object->property("c1").toInt(), 9);
905 QCOMPARE(object->property("c2").toInt(), 0);
906 QCOMPARE(object->property("c3").toInt(), 0);
908 object->setProperty("c3", QVariant(8));
909 QCOMPARE(object->property("c1").toInt(), 9);
910 QCOMPARE(object->property("c2").toInt(), 8);
911 QCOMPARE(object->property("c3").toInt(), 8);
917 Access a non-existent attached object.
919 Tests for a regression where this used to crash.
921 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
923 QDeclarativeComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
925 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
926 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
928 QObject *object = component.create();
929 QVERIFY(object != 0);
934 void tst_qdeclarativeecmascript::scope()
937 QDeclarativeComponent component(&engine, testFileUrl("scope.qml"));
938 QObject *object = component.create();
939 QVERIFY(object != 0);
941 QCOMPARE(object->property("test1").toInt(), 1);
942 QCOMPARE(object->property("test2").toInt(), 2);
943 QCOMPARE(object->property("test3").toString(), QString("1Test"));
944 QCOMPARE(object->property("test4").toString(), QString("2Test"));
945 QCOMPARE(object->property("test5").toInt(), 1);
946 QCOMPARE(object->property("test6").toInt(), 1);
947 QCOMPARE(object->property("test7").toInt(), 2);
948 QCOMPARE(object->property("test8").toInt(), 2);
949 QCOMPARE(object->property("test9").toInt(), 1);
950 QCOMPARE(object->property("test10").toInt(), 3);
956 QDeclarativeComponent component(&engine, testFileUrl("scope.2.qml"));
957 QObject *object = component.create();
958 QVERIFY(object != 0);
960 QCOMPARE(object->property("test1").toInt(), 19);
961 QCOMPARE(object->property("test2").toInt(), 19);
962 QCOMPARE(object->property("test3").toInt(), 14);
963 QCOMPARE(object->property("test4").toInt(), 14);
964 QCOMPARE(object->property("test5").toInt(), 24);
965 QCOMPARE(object->property("test6").toInt(), 24);
971 QDeclarativeComponent component(&engine, testFileUrl("scope.3.qml"));
972 QObject *object = component.create();
973 QVERIFY(object != 0);
975 QCOMPARE(object->property("test1").toBool(), true);
976 QCOMPARE(object->property("test2").toBool(), true);
977 QCOMPARE(object->property("test3").toBool(), true);
982 // Signal argument scope
984 QDeclarativeComponent component(&engine, testFileUrl("scope.4.qml"));
985 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
986 QVERIFY(object != 0);
988 QCOMPARE(object->property("test").toInt(), 0);
989 QCOMPARE(object->property("test2").toString(), QString());
991 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
993 QCOMPARE(object->property("test").toInt(), 13);
994 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
1000 QDeclarativeComponent component(&engine, testFileUrl("scope.5.qml"));
1001 QObject *object = component.create();
1002 QVERIFY(object != 0);
1004 QCOMPARE(object->property("test1").toBool(), true);
1005 QCOMPARE(object->property("test2").toBool(), true);
1011 QDeclarativeComponent component(&engine, testFileUrl("scope.6.qml"));
1012 QObject *object = component.create();
1013 QVERIFY(object != 0);
1015 QCOMPARE(object->property("test").toBool(), true);
1021 // In 4.7, non-library javascript files that had no imports shared the imports of their
1022 // importing context
1023 void tst_qdeclarativeecmascript::importScope()
1025 QDeclarativeComponent component(&engine, testFileUrl("importScope.qml"));
1026 QObject *o = component.create();
1029 QCOMPARE(o->property("test").toInt(), 240);
1035 Tests that "any" type passes through a synthesized signal parameter. This
1036 is essentially a test of QDeclarativeMetaType::copy()
1038 void tst_qdeclarativeecmascript::signalParameterTypes()
1040 QDeclarativeComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
1041 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1042 QVERIFY(object != 0);
1044 emit object->basicSignal();
1046 QCOMPARE(object->property("intProperty").toInt(), 10);
1047 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1048 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1049 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1050 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1051 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1057 Test that two JS objects for the same QObject compare as equal.
1059 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1061 QDeclarativeComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
1062 QObject *object = component.create();
1063 QVERIFY(object != 0);
1065 QCOMPARE(object->property("test1").toBool(), true);
1066 QCOMPARE(object->property("test2").toBool(), true);
1067 QCOMPARE(object->property("test3").toBool(), true);
1068 QCOMPARE(object->property("test4").toBool(), true);
1069 QCOMPARE(object->property("test5").toBool(), true);
1075 Confirm bindings and alias properties can coexist.
1077 Tests for a regression where the binding would not reevaluate.
1079 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1081 QDeclarativeComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
1082 QObject *object = component.create();
1083 QVERIFY(object != 0);
1085 QCOMPARE(object->property("c2").toInt(), 3);
1086 QCOMPARE(object->property("c3").toInt(), 3);
1088 object->setProperty("c2", QVariant(19));
1090 QCOMPARE(object->property("c2").toInt(), 19);
1091 QCOMPARE(object->property("c3").toInt(), 19);
1097 Ensure that we can write undefined value to an alias property,
1098 and that the aliased property is reset correctly if possible.
1100 void tst_qdeclarativeecmascript::aliasPropertyReset()
1102 QObject *object = 0;
1104 // test that a manual write (of undefined) to a resettable aliased property succeeds
1105 QDeclarativeComponent c1(&engine, testFileUrl("aliasreset/aliasPropertyReset.1.qml"));
1106 object = c1.create();
1107 QVERIFY(object != 0);
1108 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1109 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1110 QMetaObject::invokeMethod(object, "resetAliased");
1111 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1112 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1115 // test that a manual write (of undefined) to a resettable alias property succeeds
1116 QDeclarativeComponent c2(&engine, testFileUrl("aliasreset/aliasPropertyReset.2.qml"));
1117 object = c2.create();
1118 QVERIFY(object != 0);
1119 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1120 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1121 QMetaObject::invokeMethod(object, "resetAlias");
1122 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1123 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1126 // test that an alias to a bound property works correctly
1127 QDeclarativeComponent c3(&engine, testFileUrl("aliasreset/aliasPropertyReset.3.qml"));
1128 object = c3.create();
1129 QVERIFY(object != 0);
1130 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1131 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1132 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1133 QMetaObject::invokeMethod(object, "resetAlias");
1134 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1135 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1136 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1139 // test that a manual write (of undefined) to a resettable alias property
1140 // whose aliased property's object has been deleted, does not crash.
1141 QDeclarativeComponent c4(&engine, testFileUrl("aliasreset/aliasPropertyReset.4.qml"));
1142 object = c4.create();
1143 QVERIFY(object != 0);
1144 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1145 QObject *loader = object->findChild<QObject*>("loader");
1146 QVERIFY(loader != 0);
1148 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1149 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1150 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1151 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1152 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1155 // test that binding an alias property to an undefined value works correctly
1156 QDeclarativeComponent c5(&engine, testFileUrl("aliasreset/aliasPropertyReset.5.qml"));
1157 object = c5.create();
1158 QVERIFY(object != 0);
1159 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1162 // test that a manual write (of undefined) to a non-resettable property fails properly
1163 QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
1164 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1165 QDeclarativeComponent e1(&engine, url);
1166 object = e1.create();
1167 QVERIFY(object != 0);
1168 QCOMPARE(object->property("intAlias").value<int>(), 12);
1169 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1170 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1171 QMetaObject::invokeMethod(object, "resetAlias");
1172 QCOMPARE(object->property("intAlias").value<int>(), 12);
1173 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1177 void tst_qdeclarativeecmascript::dynamicCreation_data()
1179 QTest::addColumn<QString>("method");
1180 QTest::addColumn<QString>("createdName");
1182 QTest::newRow("One") << "createOne" << "objectOne";
1183 QTest::newRow("Two") << "createTwo" << "objectTwo";
1184 QTest::newRow("Three") << "createThree" << "objectThree";
1188 Test using createQmlObject to dynamically generate an item
1189 Also using createComponent is tested.
1191 void tst_qdeclarativeecmascript::dynamicCreation()
1193 QFETCH(QString, method);
1194 QFETCH(QString, createdName);
1196 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1197 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1198 QVERIFY(object != 0);
1200 QMetaObject::invokeMethod(object, method.toUtf8());
1201 QObject *created = object->objectProperty();
1203 QCOMPARE(created->objectName(), createdName);
1209 Tests the destroy function
1211 void tst_qdeclarativeecmascript::dynamicDestruction()
1214 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
1215 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1216 QVERIFY(object != 0);
1217 QDeclarativeGuard<QObject> createdQmlObject = 0;
1219 QMetaObject::invokeMethod(object, "create");
1220 createdQmlObject = object->objectProperty();
1221 QVERIFY(createdQmlObject);
1222 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1224 QMetaObject::invokeMethod(object, "killOther");
1225 QVERIFY(createdQmlObject);
1227 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1228 QCoreApplication::processEvents();
1229 QVERIFY(createdQmlObject);
1230 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1231 if (createdQmlObject) {
1233 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1234 QCoreApplication::processEvents();
1237 QVERIFY(!createdQmlObject);
1239 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1240 QMetaObject::invokeMethod(object, "killMe");
1242 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1243 QCoreApplication::processEvents();
1248 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
1249 QObject *o = component.create();
1252 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1254 QMetaObject::invokeMethod(o, "create");
1256 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1258 QMetaObject::invokeMethod(o, "destroy");
1260 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1261 QCoreApplication::processEvents();
1263 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1270 tests that id.toString() works
1272 void tst_qdeclarativeecmascript::objectToString()
1274 QDeclarativeComponent component(&engine, testFileUrl("declarativeToString.qml"));
1275 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1276 QVERIFY(object != 0);
1277 QMetaObject::invokeMethod(object, "testToString");
1278 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1279 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1285 tests that id.hasOwnProperty() works
1287 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1289 QUrl url = testFileUrl("declarativeHasOwnProperty.qml");
1290 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1291 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1292 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1294 QDeclarativeComponent component(&engine, url);
1295 QObject *object = component.create();
1296 QVERIFY(object != 0);
1298 // test QObjects in QML
1299 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1300 QVERIFY(object->property("result").value<bool>() == true);
1301 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1302 QVERIFY(object->property("result").value<bool>() == false);
1304 // now test other types in QML
1305 QObject *child = object->findChild<QObject*>("typeObj");
1306 QVERIFY(child != 0);
1307 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1308 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1309 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1310 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1311 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1312 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1313 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1314 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1315 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1316 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1317 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1318 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1320 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1321 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1322 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1323 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1324 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1325 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1326 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1327 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1328 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1334 Tests bindings that indirectly cause their own deletion work.
1336 This test is best run under valgrind to ensure no invalid memory access occur.
1338 void tst_qdeclarativeecmascript::selfDeletingBinding()
1341 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
1342 QObject *object = component.create();
1343 QVERIFY(object != 0);
1344 object->setProperty("triggerDelete", true);
1349 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
1350 QObject *object = component.create();
1351 QVERIFY(object != 0);
1352 object->setProperty("triggerDelete", true);
1358 Test that extended object properties can be accessed.
1360 This test a regression where this used to crash. The issue was specificially
1361 for extended objects that did not include a synthesized meta object (so non-root
1362 and no synthesiszed properties).
1364 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1366 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
1367 QObject *object = component.create();
1368 QVERIFY(object != 0);
1373 Test that extended object properties can be accessed correctly.
1375 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
1377 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
1378 QObject *object = component.create();
1379 QVERIFY(object != 0);
1381 QVariant returnValue;
1382 QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
1383 QCOMPARE(returnValue.toInt(), 42);
1388 Test file/lineNumbers for binding/Script errors.
1390 void tst_qdeclarativeecmascript::scriptErrors()
1392 QDeclarativeComponent component(&engine, testFileUrl("scriptErrors.qml"));
1393 QString url = component.url().toString();
1395 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1396 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1397 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1398 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1399 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1400 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1401 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1402 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1404 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1405 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1406 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1407 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1408 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1409 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1410 QVERIFY(object != 0);
1412 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1413 emit object->basicSignal();
1415 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1416 emit object->anotherBasicSignal();
1418 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1419 emit object->thirdBasicSignal();
1425 Test file/lineNumbers for inline functions.
1427 void tst_qdeclarativeecmascript::functionErrors()
1429 QDeclarativeComponent component(&engine, testFileUrl("functionErrors.qml"));
1430 QString url = component.url().toString();
1432 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1434 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1436 QObject *object = component.create();
1437 QVERIFY(object != 0);
1440 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1441 QDeclarativeComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
1442 url = componentTwo.url().toString();
1443 object = componentTwo.create();
1444 QVERIFY(object != 0);
1446 QString srpname = object->property("srp_name").toString();
1448 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1449 + QLatin1String(" is not a function");
1450 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1451 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1456 Test various errors that can occur when assigning a property from script
1458 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1460 QDeclarativeComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
1462 QString url = component.url().toString();
1464 QObject *object = component.create();
1465 QVERIFY(object != 0);
1467 QCOMPARE(object->property("test1").toBool(), true);
1468 QCOMPARE(object->property("test2").toBool(), true);
1474 Test bindings still work when the reeval is triggered from within
1477 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1479 QDeclarativeComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
1480 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1481 QVERIFY(object != 0);
1483 QCOMPARE(object->property("base").toReal(), 50.);
1484 QCOMPARE(object->property("test1").toReal(), 50.);
1485 QCOMPARE(object->property("test2").toReal(), 50.);
1487 object->basicSignal();
1489 QCOMPARE(object->property("base").toReal(), 200.);
1490 QCOMPARE(object->property("test1").toReal(), 200.);
1491 QCOMPARE(object->property("test2").toReal(), 200.);
1493 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1495 QCOMPARE(object->property("base").toReal(), 400.);
1496 QCOMPARE(object->property("test1").toReal(), 400.);
1497 QCOMPARE(object->property("test2").toReal(), 400.);
1503 Test that list properties can be iterated from ECMAScript
1505 void tst_qdeclarativeecmascript::listProperties()
1507 QDeclarativeComponent component(&engine, testFileUrl("listProperties.qml"));
1508 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1509 QVERIFY(object != 0);
1511 QCOMPARE(object->property("test1").toInt(), 21);
1512 QCOMPARE(object->property("test2").toInt(), 2);
1513 QCOMPARE(object->property("test3").toBool(), true);
1514 QCOMPARE(object->property("test4").toBool(), true);
1519 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1521 QDeclarativeComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
1522 QString url = component.url().toString();
1524 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1526 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1527 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1528 QVERIFY(object != 0);
1530 QCOMPARE(object->property("test").toBool(), false);
1532 MyQmlObject object2;
1533 MyQmlObject object3;
1534 object2.setObjectProperty(&object3);
1535 object->setObjectProperty(&object2);
1537 QCOMPARE(object->property("test").toBool(), true);
1542 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1544 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
1545 QString url = component.url().toString();
1547 QString warning = component.url().toString() + ":6: Error: JS exception";
1549 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1550 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1551 QVERIFY(object != 0);
1555 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1557 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
1558 QString url = component.url().toString();
1560 QString warning = component.url().toString() + ":5: Error: JS exception";
1562 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1563 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1564 QVERIFY(object != 0);
1568 void tst_qdeclarativeecmascript::compileInvalidBinding()
1570 // QTBUG-23387: ensure that invalid bindings don't cause a crash.
1571 QDeclarativeComponent component(&engine, testFileUrl("v8bindingException.qml"));
1572 QString warning = component.url().toString() + ":16: SyntaxError: Unexpected token ILLEGAL";
1573 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1574 QObject *object = component.create();
1575 QVERIFY(object != 0);
1579 static int transientErrorsMsgCount = 0;
1580 static void transientErrorsMsgHandler(QtMsgType, const char *)
1582 ++transientErrorsMsgCount;
1585 // Check that transient binding errors are not displayed
1586 void tst_qdeclarativeecmascript::transientErrors()
1589 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
1591 transientErrorsMsgCount = 0;
1592 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1594 QObject *object = component.create();
1595 QVERIFY(object != 0);
1597 qInstallMsgHandler(old);
1599 QCOMPARE(transientErrorsMsgCount, 0);
1604 // One binding erroring multiple times, but then resolving
1606 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
1608 transientErrorsMsgCount = 0;
1609 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1611 QObject *object = component.create();
1612 QVERIFY(object != 0);
1614 qInstallMsgHandler(old);
1616 QCOMPARE(transientErrorsMsgCount, 0);
1622 // Check that errors during shutdown are minimized
1623 void tst_qdeclarativeecmascript::shutdownErrors()
1625 QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
1626 QObject *object = component.create();
1627 QVERIFY(object != 0);
1629 transientErrorsMsgCount = 0;
1630 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1634 qInstallMsgHandler(old);
1635 QCOMPARE(transientErrorsMsgCount, 0);
1638 void tst_qdeclarativeecmascript::compositePropertyType()
1640 QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
1642 QTest::ignoreMessage(QtDebugMsg, "hello world");
1643 QObject *object = qobject_cast<QObject *>(component.create());
1648 void tst_qdeclarativeecmascript::jsObject()
1650 QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
1651 QObject *object = component.create();
1652 QVERIFY(object != 0);
1654 QCOMPARE(object->property("test").toInt(), 92);
1659 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1662 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
1663 QObject *object = component.create();
1664 QVERIFY(object != 0);
1666 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1668 object->setProperty("setUndefined", true);
1670 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1672 object->setProperty("setUndefined", false);
1674 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1679 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
1680 QObject *object = component.create();
1681 QVERIFY(object != 0);
1683 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1685 QMetaObject::invokeMethod(object, "doReset");
1687 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1693 // Aliases to variant properties should work
1694 void tst_qdeclarativeecmascript::qtbug_22464()
1696 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
1697 QObject *object = component.create();
1698 QVERIFY(object != 0);
1700 QCOMPARE(object->property("test").toBool(), true);
1705 void tst_qdeclarativeecmascript::qtbug_21580()
1707 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
1709 QObject *object = component.create();
1710 QVERIFY(object != 0);
1712 QCOMPARE(object->property("test").toBool(), true);
1718 void tst_qdeclarativeecmascript::bug1()
1720 QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
1721 QObject *object = component.create();
1722 QVERIFY(object != 0);
1724 QCOMPARE(object->property("test").toInt(), 14);
1726 object->setProperty("a", 11);
1728 QCOMPARE(object->property("test").toInt(), 3);
1730 object->setProperty("b", true);
1732 QCOMPARE(object->property("test").toInt(), 9);
1737 void tst_qdeclarativeecmascript::bug2()
1739 QDeclarativeComponent component(&engine);
1740 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1742 QObject *object = component.create();
1743 QVERIFY(object != 0);
1748 // Don't crash in createObject when the component has errors.
1749 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1751 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1752 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1753 QVERIFY(object != 0);
1755 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1756 QMetaObject::invokeMethod(object, "dontCrash");
1757 QObject *created = object->objectProperty();
1758 QVERIFY(created == 0);
1763 // ownership transferred to JS, ensure that GC runs the dtor
1764 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1767 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1769 // allow the engine to go out of scope too.
1771 QDeclarativeEngine dcoEngine;
1772 QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
1773 QObject *object = component.create();
1774 QVERIFY(object != 0);
1775 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1776 QVERIFY(mdcdo != 0);
1777 mdcdo->setDtorCount(&dtorCount);
1779 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1780 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1782 // we do this once manually, but it should be done automatically
1783 // when the engine goes out of scope (since it should gc in dtor)
1784 QMetaObject::invokeMethod(object, "performGc");
1787 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1788 QCoreApplication::processEvents();
1794 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1795 QCoreApplication::processEvents();
1796 QCOMPARE(dtorCount, expectedDtorCount);
1799 void tst_qdeclarativeecmascript::regExpBug()
1803 QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
1804 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1805 QVERIFY(object != 0);
1806 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1812 QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
1813 QDeclarativeComponent component(&engine, testFileUrl("regExp.2.qml"));
1814 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1815 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1817 QCOMPARE(component.errorString(), err);
1821 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1823 QString functionSource = QLatin1String("(function(object) { return ") +
1824 QLatin1String(source) + QLatin1String(" })");
1826 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1829 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1830 if (function.IsEmpty())
1832 v8::Handle<v8::Value> args[] = { o };
1833 function->Call(engine->global(), 1, args);
1834 return tc.HasCaught();
1837 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1838 const char *source, v8::Handle<v8::Value> result)
1840 QString functionSource = QLatin1String("(function(object) { return ") +
1841 QLatin1String(source) + QLatin1String(" })");
1843 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1846 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1847 if (function.IsEmpty())
1849 v8::Handle<v8::Value> args[] = { o };
1851 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1856 return value->StrictEquals(result);
1859 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1862 QString functionSource = QLatin1String("(function(object) { return ") +
1863 QLatin1String(source) + QLatin1String(" })");
1865 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1867 return v8::Handle<v8::Value>();
1868 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1869 if (function.IsEmpty())
1870 return v8::Handle<v8::Value>();
1871 v8::Handle<v8::Value> args[] = { o };
1873 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1876 return v8::Handle<v8::Value>();
1880 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1881 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1882 #define EVALUATE(source) evaluate(engine, object, source)
1884 void tst_qdeclarativeecmascript::callQtInvokables()
1886 MyInvokableObject o;
1888 QDeclarativeEngine qmlengine;
1889 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1891 QV8Engine *engine = ep->v8engine();
1893 v8::HandleScope handle_scope;
1894 v8::Context::Scope scope(engine->context());
1896 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1898 // Non-existent methods
1900 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1901 QCOMPARE(o.error(), false);
1902 QCOMPARE(o.invoked(), -1);
1903 QCOMPARE(o.actuals().count(), 0);
1906 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1907 QCOMPARE(o.error(), false);
1908 QCOMPARE(o.invoked(), -1);
1909 QCOMPARE(o.actuals().count(), 0);
1911 // Insufficient arguments
1913 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1914 QCOMPARE(o.error(), false);
1915 QCOMPARE(o.invoked(), -1);
1916 QCOMPARE(o.actuals().count(), 0);
1919 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1920 QCOMPARE(o.error(), false);
1921 QCOMPARE(o.invoked(), -1);
1922 QCOMPARE(o.actuals().count(), 0);
1924 // Excessive arguments
1926 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1927 QCOMPARE(o.error(), false);
1928 QCOMPARE(o.invoked(), 8);
1929 QCOMPARE(o.actuals().count(), 1);
1930 QCOMPARE(o.actuals().at(0), QVariant(10));
1933 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1934 QCOMPARE(o.error(), false);
1935 QCOMPARE(o.invoked(), 9);
1936 QCOMPARE(o.actuals().count(), 2);
1937 QCOMPARE(o.actuals().at(0), QVariant(10));
1938 QCOMPARE(o.actuals().at(1), QVariant(11));
1940 // Test return types
1942 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1943 QCOMPARE(o.error(), false);
1944 QCOMPARE(o.invoked(), 0);
1945 QCOMPARE(o.actuals().count(), 0);
1948 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1949 QCOMPARE(o.error(), false);
1950 QCOMPARE(o.invoked(), 1);
1951 QCOMPARE(o.actuals().count(), 0);
1954 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1955 QCOMPARE(o.error(), false);
1956 QCOMPARE(o.invoked(), 2);
1957 QCOMPARE(o.actuals().count(), 0);
1961 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1962 QVERIFY(!ret.IsEmpty());
1963 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1964 QCOMPARE(o.error(), false);
1965 QCOMPARE(o.invoked(), 3);
1966 QCOMPARE(o.actuals().count(), 0);
1971 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1972 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1973 QCOMPARE(o.error(), false);
1974 QCOMPARE(o.invoked(), 4);
1975 QCOMPARE(o.actuals().count(), 0);
1979 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1980 QCOMPARE(o.error(), false);
1981 QCOMPARE(o.invoked(), 5);
1982 QCOMPARE(o.actuals().count(), 0);
1986 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1987 QVERIFY(ret->IsString());
1988 QCOMPARE(engine->toString(ret), QString("Hello world"));
1989 QCOMPARE(o.error(), false);
1990 QCOMPARE(o.invoked(), 6);
1991 QCOMPARE(o.actuals().count(), 0);
1995 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1996 QCOMPARE(o.error(), false);
1997 QCOMPARE(o.invoked(), 7);
1998 QCOMPARE(o.actuals().count(), 0);
2002 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
2003 QCOMPARE(o.error(), false);
2004 QCOMPARE(o.invoked(), 8);
2005 QCOMPARE(o.actuals().count(), 1);
2006 QCOMPARE(o.actuals().at(0), QVariant(94));
2009 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
2010 QCOMPARE(o.error(), false);
2011 QCOMPARE(o.invoked(), 8);
2012 QCOMPARE(o.actuals().count(), 1);
2013 QCOMPARE(o.actuals().at(0), QVariant(94));
2016 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
2017 QCOMPARE(o.error(), false);
2018 QCOMPARE(o.invoked(), 8);
2019 QCOMPARE(o.actuals().count(), 1);
2020 QCOMPARE(o.actuals().at(0), QVariant(0));
2023 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
2024 QCOMPARE(o.error(), false);
2025 QCOMPARE(o.invoked(), 8);
2026 QCOMPARE(o.actuals().count(), 1);
2027 QCOMPARE(o.actuals().at(0), QVariant(0));
2030 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
2031 QCOMPARE(o.error(), false);
2032 QCOMPARE(o.invoked(), 8);
2033 QCOMPARE(o.actuals().count(), 1);
2034 QCOMPARE(o.actuals().at(0), QVariant(0));
2037 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2038 QCOMPARE(o.error(), false);
2039 QCOMPARE(o.invoked(), 8);
2040 QCOMPARE(o.actuals().count(), 1);
2041 QCOMPARE(o.actuals().at(0), QVariant(0));
2044 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2045 QCOMPARE(o.error(), false);
2046 QCOMPARE(o.invoked(), 9);
2047 QCOMPARE(o.actuals().count(), 2);
2048 QCOMPARE(o.actuals().at(0), QVariant(122));
2049 QCOMPARE(o.actuals().at(1), QVariant(9));
2052 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2053 QCOMPARE(o.error(), false);
2054 QCOMPARE(o.invoked(), 10);
2055 QCOMPARE(o.actuals().count(), 1);
2056 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2059 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2060 QCOMPARE(o.error(), false);
2061 QCOMPARE(o.invoked(), 10);
2062 QCOMPARE(o.actuals().count(), 1);
2063 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2066 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2067 QCOMPARE(o.error(), false);
2068 QCOMPARE(o.invoked(), 10);
2069 QCOMPARE(o.actuals().count(), 1);
2070 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2073 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2074 QCOMPARE(o.error(), false);
2075 QCOMPARE(o.invoked(), 10);
2076 QCOMPARE(o.actuals().count(), 1);
2077 QCOMPARE(o.actuals().at(0), QVariant(0));
2080 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2081 QCOMPARE(o.error(), false);
2082 QCOMPARE(o.invoked(), 10);
2083 QCOMPARE(o.actuals().count(), 1);
2084 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2087 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2088 QCOMPARE(o.error(), false);
2089 QCOMPARE(o.invoked(), 10);
2090 QCOMPARE(o.actuals().count(), 1);
2091 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2094 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2095 QCOMPARE(o.error(), false);
2096 QCOMPARE(o.invoked(), 11);
2097 QCOMPARE(o.actuals().count(), 1);
2098 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2101 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2102 QCOMPARE(o.error(), false);
2103 QCOMPARE(o.invoked(), 11);
2104 QCOMPARE(o.actuals().count(), 1);
2105 QCOMPARE(o.actuals().at(0), QVariant("19"));
2109 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2110 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2111 QCOMPARE(o.error(), false);
2112 QCOMPARE(o.invoked(), 11);
2113 QCOMPARE(o.actuals().count(), 1);
2114 QCOMPARE(o.actuals().at(0), QVariant(expected));
2118 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2119 QCOMPARE(o.error(), false);
2120 QCOMPARE(o.invoked(), 11);
2121 QCOMPARE(o.actuals().count(), 1);
2122 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2125 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2126 QCOMPARE(o.error(), false);
2127 QCOMPARE(o.invoked(), 11);
2128 QCOMPARE(o.actuals().count(), 1);
2129 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2132 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2133 QCOMPARE(o.error(), false);
2134 QCOMPARE(o.invoked(), 12);
2135 QCOMPARE(o.actuals().count(), 1);
2136 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2139 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2140 QCOMPARE(o.error(), false);
2141 QCOMPARE(o.invoked(), 12);
2142 QCOMPARE(o.actuals().count(), 1);
2143 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2146 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2147 QCOMPARE(o.error(), false);
2148 QCOMPARE(o.invoked(), 12);
2149 QCOMPARE(o.actuals().count(), 1);
2150 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2153 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2154 QCOMPARE(o.error(), false);
2155 QCOMPARE(o.invoked(), 12);
2156 QCOMPARE(o.actuals().count(), 1);
2157 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2160 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2161 QCOMPARE(o.error(), false);
2162 QCOMPARE(o.invoked(), 12);
2163 QCOMPARE(o.actuals().count(), 1);
2164 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2167 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2168 QCOMPARE(o.error(), false);
2169 QCOMPARE(o.invoked(), 12);
2170 QCOMPARE(o.actuals().count(), 1);
2171 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2174 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2175 QCOMPARE(o.error(), false);
2176 QCOMPARE(o.invoked(), 13);
2177 QCOMPARE(o.actuals().count(), 1);
2178 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2181 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2182 QCOMPARE(o.error(), false);
2183 QCOMPARE(o.invoked(), 13);
2184 QCOMPARE(o.actuals().count(), 1);
2185 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2188 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2189 QCOMPARE(o.error(), false);
2190 QCOMPARE(o.invoked(), 13);
2191 QCOMPARE(o.actuals().count(), 1);
2192 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2195 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2196 QCOMPARE(o.error(), false);
2197 QCOMPARE(o.invoked(), 13);
2198 QCOMPARE(o.actuals().count(), 1);
2199 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2202 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2203 QCOMPARE(o.error(), false);
2204 QCOMPARE(o.invoked(), 13);
2205 QCOMPARE(o.actuals().count(), 1);
2206 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2209 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2210 QCOMPARE(o.error(), false);
2211 QCOMPARE(o.invoked(), 14);
2212 QCOMPARE(o.actuals().count(), 1);
2213 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2216 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2217 QCOMPARE(o.error(), false);
2218 QCOMPARE(o.invoked(), 14);
2219 QCOMPARE(o.actuals().count(), 1);
2220 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2223 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2224 QCOMPARE(o.error(), false);
2225 QCOMPARE(o.invoked(), 14);
2226 QCOMPARE(o.actuals().count(), 1);
2227 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2230 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2231 QCOMPARE(o.error(), false);
2232 QCOMPARE(o.invoked(), 14);
2233 QCOMPARE(o.actuals().count(), 1);
2234 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2237 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2238 QCOMPARE(o.error(), false);
2239 QCOMPARE(o.invoked(), 15);
2240 QCOMPARE(o.actuals().count(), 2);
2241 QCOMPARE(o.actuals().at(0), QVariant(4));
2242 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2245 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2246 QCOMPARE(o.error(), false);
2247 QCOMPARE(o.invoked(), 15);
2248 QCOMPARE(o.actuals().count(), 2);
2249 QCOMPARE(o.actuals().at(0), QVariant(8));
2250 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2253 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2254 QCOMPARE(o.error(), false);
2255 QCOMPARE(o.invoked(), 15);
2256 QCOMPARE(o.actuals().count(), 2);
2257 QCOMPARE(o.actuals().at(0), QVariant(3));
2258 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2261 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2262 QCOMPARE(o.error(), false);
2263 QCOMPARE(o.invoked(), 15);
2264 QCOMPARE(o.actuals().count(), 2);
2265 QCOMPARE(o.actuals().at(0), QVariant(44));
2266 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2269 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2270 QCOMPARE(o.error(), false);
2271 QCOMPARE(o.invoked(), -1);
2272 QCOMPARE(o.actuals().count(), 0);
2275 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2276 QCOMPARE(o.error(), false);
2277 QCOMPARE(o.invoked(), 16);
2278 QCOMPARE(o.actuals().count(), 1);
2279 QCOMPARE(o.actuals().at(0), QVariant(10));
2282 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2283 QCOMPARE(o.error(), false);
2284 QCOMPARE(o.invoked(), 17);
2285 QCOMPARE(o.actuals().count(), 2);
2286 QCOMPARE(o.actuals().at(0), QVariant(10));
2287 QCOMPARE(o.actuals().at(1), QVariant(11));
2290 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2291 QCOMPARE(o.error(), false);
2292 QCOMPARE(o.invoked(), 18);
2293 QCOMPARE(o.actuals().count(), 1);
2294 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2297 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2298 QCOMPARE(o.error(), false);
2299 QCOMPARE(o.invoked(), 19);
2300 QCOMPARE(o.actuals().count(), 1);
2301 QCOMPARE(o.actuals().at(0), QVariant(9));
2304 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2305 QCOMPARE(o.error(), false);
2306 QCOMPARE(o.invoked(), 20);
2307 QCOMPARE(o.actuals().count(), 2);
2308 QCOMPARE(o.actuals().at(0), QVariant(10));
2309 QCOMPARE(o.actuals().at(1), QVariant(19));
2312 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2313 QCOMPARE(o.error(), false);
2314 QCOMPARE(o.invoked(), 20);
2315 QCOMPARE(o.actuals().count(), 2);
2316 QCOMPARE(o.actuals().at(0), QVariant(10));
2317 QCOMPARE(o.actuals().at(1), QVariant(13));
2320 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2321 QCOMPARE(o.error(), false);
2322 QCOMPARE(o.invoked(), -3);
2323 QCOMPARE(o.actuals().count(), 1);
2324 QCOMPARE(o.actuals().at(0), QVariant(9));
2327 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2328 QCOMPARE(o.error(), false);
2329 QCOMPARE(o.invoked(), 21);
2330 QCOMPARE(o.actuals().count(), 2);
2331 QCOMPARE(o.actuals().at(0), QVariant(9));
2332 QCOMPARE(o.actuals().at(1), QVariant());
2335 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2336 QCOMPARE(o.error(), false);
2337 QCOMPARE(o.invoked(), 21);
2338 QCOMPARE(o.actuals().count(), 2);
2339 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2340 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2343 // QTBUG-13047 (check that you can pass registered object types as args)
2344 void tst_qdeclarativeecmascript::invokableObjectArg()
2346 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
2348 QObject *o = component.create();
2350 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2352 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2357 // QTBUG-13047 (check that you can return registered object types from methods)
2358 void tst_qdeclarativeecmascript::invokableObjectRet()
2360 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
2362 QObject *o = component.create();
2364 QCOMPARE(o->property("test").toBool(), true);
2369 void tst_qdeclarativeecmascript::listToVariant()
2371 QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
2373 MyQmlContainer container;
2375 QDeclarativeContext context(engine.rootContext());
2376 context.setContextObject(&container);
2378 QObject *object = component.create(&context);
2379 QVERIFY(object != 0);
2381 QVariant v = object->property("test");
2382 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2383 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2389 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2390 void tst_qdeclarativeecmascript::listAssignment()
2392 QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
2393 QObject *obj = component.create();
2394 QCOMPARE(obj->property("list1length").toInt(), 2);
2395 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2396 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2397 QCOMPARE(list1.count(&list1), list2.count(&list2));
2398 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2399 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2404 void tst_qdeclarativeecmascript::multiEngineObject()
2407 obj.setStringProperty("Howdy planet");
2409 QDeclarativeEngine e1;
2410 e1.rootContext()->setContextProperty("thing", &obj);
2411 QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
2413 QDeclarativeEngine e2;
2414 e2.rootContext()->setContextProperty("thing", &obj);
2415 QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
2417 QObject *o1 = c1.create();
2418 QObject *o2 = c2.create();
2420 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2421 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2427 // Test that references to QObjects are cleanup when the object is destroyed
2428 void tst_qdeclarativeecmascript::deletedObject()
2430 QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
2432 QObject *object = component.create();
2434 QCOMPARE(object->property("test1").toBool(), true);
2435 QCOMPARE(object->property("test2").toBool(), true);
2436 QCOMPARE(object->property("test3").toBool(), true);
2437 QCOMPARE(object->property("test4").toBool(), true);
2442 void tst_qdeclarativeecmascript::attachedPropertyScope()
2444 QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
2446 QObject *object = component.create();
2447 QVERIFY(object != 0);
2449 MyQmlAttachedObject *attached =
2450 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2451 QVERIFY(attached != 0);
2453 QCOMPARE(object->property("value2").toInt(), 0);
2455 attached->emitMySignal();
2457 QCOMPARE(object->property("value2").toInt(), 9);
2462 void tst_qdeclarativeecmascript::scriptConnect()
2465 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
2467 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2468 QVERIFY(object != 0);
2470 QCOMPARE(object->property("test").toBool(), false);
2471 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2472 QCOMPARE(object->property("test").toBool(), true);
2478 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
2480 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2481 QVERIFY(object != 0);
2483 QCOMPARE(object->property("test").toBool(), false);
2484 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2485 QCOMPARE(object->property("test").toBool(), true);
2491 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
2493 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2494 QVERIFY(object != 0);
2496 QCOMPARE(object->property("test").toBool(), false);
2497 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2498 QCOMPARE(object->property("test").toBool(), true);
2504 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
2506 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2507 QVERIFY(object != 0);
2509 QCOMPARE(object->methodCalled(), false);
2510 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2511 QCOMPARE(object->methodCalled(), true);
2517 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
2519 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2520 QVERIFY(object != 0);
2522 QCOMPARE(object->methodCalled(), false);
2523 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2524 QCOMPARE(object->methodCalled(), true);
2530 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
2532 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2533 QVERIFY(object != 0);
2535 QCOMPARE(object->property("test").toInt(), 0);
2536 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2537 QCOMPARE(object->property("test").toInt(), 2);
2543 void tst_qdeclarativeecmascript::scriptDisconnect()
2546 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
2548 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2549 QVERIFY(object != 0);
2551 QCOMPARE(object->property("test").toInt(), 0);
2552 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2553 QCOMPARE(object->property("test").toInt(), 1);
2554 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2555 QCOMPARE(object->property("test").toInt(), 2);
2556 emit object->basicSignal();
2557 QCOMPARE(object->property("test").toInt(), 2);
2558 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2559 QCOMPARE(object->property("test").toInt(), 2);
2565 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
2567 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2568 QVERIFY(object != 0);
2570 QCOMPARE(object->property("test").toInt(), 0);
2571 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2572 QCOMPARE(object->property("test").toInt(), 1);
2573 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2574 QCOMPARE(object->property("test").toInt(), 2);
2575 emit object->basicSignal();
2576 QCOMPARE(object->property("test").toInt(), 2);
2577 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2578 QCOMPARE(object->property("test").toInt(), 2);
2584 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
2586 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2587 QVERIFY(object != 0);
2589 QCOMPARE(object->property("test").toInt(), 0);
2590 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2591 QCOMPARE(object->property("test").toInt(), 1);
2592 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2593 QCOMPARE(object->property("test").toInt(), 2);
2594 emit object->basicSignal();
2595 QCOMPARE(object->property("test").toInt(), 2);
2596 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2597 QCOMPARE(object->property("test").toInt(), 3);
2602 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
2604 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2605 QVERIFY(object != 0);
2607 QCOMPARE(object->property("test").toInt(), 0);
2608 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2609 QCOMPARE(object->property("test").toInt(), 1);
2610 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2611 QCOMPARE(object->property("test").toInt(), 2);
2612 emit object->basicSignal();
2613 QCOMPARE(object->property("test").toInt(), 2);
2614 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2615 QCOMPARE(object->property("test").toInt(), 3);
2621 class OwnershipObject : public QObject
2625 OwnershipObject() { object = new QObject; }
2627 QPointer<QObject> object;
2630 QObject *getObject() { return object; }
2633 void tst_qdeclarativeecmascript::ownership()
2635 OwnershipObject own;
2636 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2637 context->setContextObject(&own);
2640 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2642 QVERIFY(own.object != 0);
2644 QObject *object = component.create(context);
2646 engine.collectGarbage();
2648 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2649 QCoreApplication::processEvents();
2651 QVERIFY(own.object == 0);
2656 own.object = new QObject(&own);
2659 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2661 QVERIFY(own.object != 0);
2663 QObject *object = component.create(context);
2665 engine.collectGarbage();
2667 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2668 QCoreApplication::processEvents();
2670 QVERIFY(own.object != 0);
2678 class CppOwnershipReturnValue : public QObject
2682 CppOwnershipReturnValue() : value(0) {}
2683 ~CppOwnershipReturnValue() { delete value; }
2685 Q_INVOKABLE QObject *create() {
2686 value = new QObject;
2687 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2691 Q_INVOKABLE MyQmlObject *createQmlObject() {
2692 MyQmlObject *rv = new MyQmlObject;
2697 QPointer<QObject> value;
2701 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2702 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2704 CppOwnershipReturnValue source;
2707 QDeclarativeEngine engine;
2708 engine.rootContext()->setContextProperty("source", &source);
2710 QVERIFY(source.value == 0);
2712 QDeclarativeComponent component(&engine);
2713 component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2715 QObject *object = component.create();
2717 QVERIFY(object != 0);
2718 QVERIFY(source.value != 0);
2723 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2724 QCoreApplication::processEvents();
2726 QVERIFY(source.value != 0);
2730 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2732 CppOwnershipReturnValue source;
2735 QDeclarativeEngine engine;
2736 engine.rootContext()->setContextProperty("source", &source);
2738 QVERIFY(source.value == 0);
2740 QDeclarativeComponent component(&engine);
2741 component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2743 QObject *object = component.create();
2745 QVERIFY(object != 0);
2746 QVERIFY(source.value != 0);
2751 engine.collectGarbage();
2752 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2753 QCoreApplication::processEvents();
2755 QVERIFY(source.value == 0);
2758 class QListQObjectMethodsObject : public QObject
2762 QListQObjectMethodsObject() {
2763 m_objects.append(new MyQmlObject());
2764 m_objects.append(new MyQmlObject());
2767 ~QListQObjectMethodsObject() {
2768 qDeleteAll(m_objects);
2772 QList<QObject *> getObjects() { return m_objects; }
2775 QList<QObject *> m_objects;
2778 // Tests that returning a QList<QObject*> from a method works
2779 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2781 QListQObjectMethodsObject obj;
2782 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2783 context->setContextObject(&obj);
2785 QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
2787 QObject *object = component.create(context);
2789 QCOMPARE(object->property("test").toInt(), 2);
2790 QCOMPARE(object->property("test2").toBool(), true);
2797 void tst_qdeclarativeecmascript::strictlyEquals()
2799 QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
2801 QObject *object = component.create();
2802 QVERIFY(object != 0);
2804 QCOMPARE(object->property("test1").toBool(), true);
2805 QCOMPARE(object->property("test2").toBool(), true);
2806 QCOMPARE(object->property("test3").toBool(), true);
2807 QCOMPARE(object->property("test4").toBool(), true);
2808 QCOMPARE(object->property("test5").toBool(), true);
2809 QCOMPARE(object->property("test6").toBool(), true);
2810 QCOMPARE(object->property("test7").toBool(), true);
2811 QCOMPARE(object->property("test8").toBool(), true);
2816 void tst_qdeclarativeecmascript::compiled()
2818 QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
2820 QObject *object = component.create();
2821 QVERIFY(object != 0);
2823 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2824 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2825 QCOMPARE(object->property("test3").toBool(), true);
2826 QCOMPARE(object->property("test4").toBool(), false);
2827 QCOMPARE(object->property("test5").toBool(), false);
2828 QCOMPARE(object->property("test6").toBool(), true);
2830 QCOMPARE(object->property("test7").toInt(), 185);
2831 QCOMPARE(object->property("test8").toInt(), 167);
2832 QCOMPARE(object->property("test9").toBool(), true);
2833 QCOMPARE(object->property("test10").toBool(), false);
2834 QCOMPARE(object->property("test11").toBool(), false);
2835 QCOMPARE(object->property("test12").toBool(), true);
2837 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2838 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2839 QCOMPARE(object->property("test15").toBool(), false);
2840 QCOMPARE(object->property("test16").toBool(), true);
2842 QCOMPARE(object->property("test17").toInt(), 5);
2843 QCOMPARE(object->property("test18").toReal(), qreal(176));
2844 QCOMPARE(object->property("test19").toInt(), 7);
2845 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2846 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2847 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2848 QCOMPARE(object->property("test23").toBool(), true);
2849 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2850 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2855 // Test that numbers assigned in bindings as strings work consistently
2856 void tst_qdeclarativeecmascript::numberAssignment()
2858 QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
2860 QObject *object = component.create();
2861 QVERIFY(object != 0);
2863 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2864 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2865 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2866 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2867 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2869 QCOMPARE(object->property("test5"), QVariant((int)7));
2870 QCOMPARE(object->property("test6"), QVariant((int)7));
2871 QCOMPARE(object->property("test7"), QVariant((int)6));
2872 QCOMPARE(object->property("test8"), QVariant((int)6));
2874 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2875 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2876 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2877 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2882 void tst_qdeclarativeecmascript::propertySplicing()
2884 QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
2886 QObject *object = component.create();
2887 QVERIFY(object != 0);
2889 QCOMPARE(object->property("test").toBool(), true);
2895 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2897 QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
2899 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2900 QVERIFY(object != 0);
2902 MyQmlObject::MyType type;
2903 type.value = 0x8971123;
2904 emit object->signalWithUnknownType(type);
2906 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2908 QCOMPARE(result.value, type.value);
2914 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2916 QTest::addColumn<QString>("expression");
2917 QTest::addColumn<QString>("compare");
2919 QString compareStrict("(function(a, b) { return a === b; })");
2920 QTest::newRow("true") << "true" << compareStrict;
2921 QTest::newRow("undefined") << "undefined" << compareStrict;
2922 QTest::newRow("null") << "null" << compareStrict;
2923 QTest::newRow("123") << "123" << compareStrict;
2924 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2926 QString comparePropertiesStrict(
2928 " if (typeof b != 'object')"
2930 " var props = Object.getOwnPropertyNames(b);"
2931 " for (var i = 0; i < props.length; ++i) {"
2932 " var p = props[i];"
2933 " return arguments.callee(a[p], b[p]);"
2936 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2937 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2940 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2942 QFETCH(QString, expression);
2943 QFETCH(QString, compare);
2945 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2946 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2947 QVERIFY(object != 0);
2949 QJSValue value = engine.evaluate(expression);
2950 QVERIFY(!engine.hasUncaughtException());
2951 object->setProperty("expression", expression);
2952 object->setProperty("compare", compare);
2953 object->setProperty("pass", false);
2955 emit object->signalWithVariant(QVariant::fromValue(value));
2956 QVERIFY(object->property("pass").toBool());
2959 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2961 signalWithJSValueInVariant_data();
2964 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2966 QFETCH(QString, expression);
2967 QFETCH(QString, compare);
2969 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2970 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2971 QVERIFY(object != 0);
2974 QJSValue value = engine2.evaluate(expression);
2975 QVERIFY(!engine2.hasUncaughtException());
2976 object->setProperty("expression", expression);
2977 object->setProperty("compare", compare);
2978 object->setProperty("pass", false);
2980 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2981 emit object->signalWithVariant(QVariant::fromValue(value));
2982 QVERIFY(!object->property("pass").toBool());
2985 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2987 signalWithJSValueInVariant_data();
2990 void tst_qdeclarativeecmascript::signalWithQJSValue()
2992 QFETCH(QString, expression);
2993 QFETCH(QString, compare);
2995 QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
2996 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2997 QVERIFY(object != 0);
2999 QJSValue value = engine.evaluate(expression);
3000 QVERIFY(!engine.hasUncaughtException());
3001 object->setProperty("expression", expression);
3002 object->setProperty("compare", compare);
3003 object->setProperty("pass", false);
3005 emit object->signalWithQJSValue(value);
3007 QVERIFY(object->property("pass").toBool());
3008 QVERIFY(object->qjsvalue().strictlyEquals(value));
3011 void tst_qdeclarativeecmascript::moduleApi_data()
3013 QTest::addColumn<QUrl>("testfile");
3014 QTest::addColumn<QString>("errorMessage");
3015 QTest::addColumn<QStringList>("warningMessages");
3016 QTest::addColumn<QStringList>("readProperties");
3017 QTest::addColumn<QVariantList>("readExpectedValues");
3018 QTest::addColumn<QStringList>("writeProperties");
3019 QTest::addColumn<QVariantList>("writeValues");
3020 QTest::addColumn<QStringList>("readBackProperties");
3021 QTest::addColumn<QVariantList>("readBackExpectedValues");
3023 QTest::newRow("qobject, register + read + method")
3024 << testFileUrl("moduleapi/qobjectModuleApi.qml")
3027 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
3028 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
3029 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
3035 QTest::newRow("script, register + read")
3036 << testFileUrl("moduleapi/scriptModuleApi.qml")
3039 << (QStringList() << "scriptTest")
3040 << (QVariantList() << 13)
3046 QTest::newRow("qobject, caching + read")
3047 << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
3050 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3051 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3057 QTest::newRow("script, caching + read")
3058 << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
3061 << (QStringList() << "scriptTest")
3062 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3068 QTest::newRow("qobject, writing + readonly constraints")
3069 << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
3071 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3072 << (QStringList() << "readOnlyProperty" << "writableProperty")
3073 << (QVariantList() << 20 << 50)
3074 << (QStringList() << "firstProperty" << "writableProperty")
3075 << (QVariantList() << 30 << 30)
3076 << (QStringList() << "readOnlyProperty" << "writableProperty")
3077 << (QVariantList() << 20 << 30);
3079 QTest::newRow("script, writing + readonly constraints")
3080 << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
3082 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3083 << (QStringList() << "readBack" << "unchanged")
3084 << (QVariantList() << 13 << 42)
3085 << (QStringList() << "firstProperty" << "secondProperty")
3086 << (QVariantList() << 30 << 30)
3087 << (QStringList() << "readBack" << "unchanged")
3088 << (QVariantList() << 30 << 42);
3090 QTest::newRow("qobject module API enum values in JS")
3091 << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
3094 << (QStringList() << "enumValue" << "enumMethod")
3095 << (QVariantList() << 42 << 30)
3101 QTest::newRow("qobject, invalid major version fail")
3102 << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
3103 << QString("QDeclarativeComponent: Component is not ready")
3112 QTest::newRow("qobject, invalid minor version fail")
3113 << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
3114 << QString("QDeclarativeComponent: Component is not ready")
3124 void tst_qdeclarativeecmascript::moduleApi()
3126 QFETCH(QUrl, testfile);
3127 QFETCH(QString, errorMessage);
3128 QFETCH(QStringList, warningMessages);
3129 QFETCH(QStringList, readProperties);
3130 QFETCH(QVariantList, readExpectedValues);
3131 QFETCH(QStringList, writeProperties);
3132 QFETCH(QVariantList, writeValues);
3133 QFETCH(QStringList, readBackProperties);
3134 QFETCH(QVariantList, readBackExpectedValues);
3136 QDeclarativeComponent component(&engine, testfile);
3138 if (!errorMessage.isEmpty())
3139 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3141 if (warningMessages.size())
3142 foreach (const QString &warning, warningMessages)
3143 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3145 QObject *object = component.create();
3146 if (!errorMessage.isEmpty()) {
3147 QVERIFY(object == 0);
3149 QVERIFY(object != 0);
3150 for (int i = 0; i < readProperties.size(); ++i)
3151 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3152 for (int i = 0; i < writeProperties.size(); ++i)
3153 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3154 for (int i = 0; i < readBackProperties.size(); ++i)
3155 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3160 void tst_qdeclarativeecmascript::importScripts_data()
3162 QTest::addColumn<QUrl>("testfile");
3163 QTest::addColumn<QString>("errorMessage");
3164 QTest::addColumn<QStringList>("warningMessages");
3165 QTest::addColumn<QStringList>("propertyNames");
3166 QTest::addColumn<QVariantList>("propertyValues");
3168 QTest::newRow("basic functionality")
3169 << testFileUrl("jsimport/testImport.qml")
3172 << (QStringList() << QLatin1String("importedScriptStringValue")
3173 << QLatin1String("importedScriptFunctionValue")
3174 << QLatin1String("importedModuleAttachedPropertyValue")
3175 << QLatin1String("importedModuleEnumValue"))
3176 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3181 QTest::newRow("import scoping")
3182 << testFileUrl("jsimport/testImportScoping.qml")
3185 << (QStringList() << QLatin1String("componentError"))
3186 << (QVariantList() << QVariant(5));
3188 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3189 << testFileUrl("jsimportfail/failOne.qml")
3191 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3192 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3193 << (QVariantList() << QVariant(QString()));
3195 QTest::newRow("javascript imports in an import should be private to the import scope")
3196 << testFileUrl("jsimportfail/failTwo.qml")
3198 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3199 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3200 << (QVariantList() << QVariant(QString()));
3202 QTest::newRow("module imports in an import should be private to the import scope")
3203 << testFileUrl("jsimportfail/failThree.qml")
3205 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3206 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3207 << (QVariantList() << QVariant(false));
3209 QTest::newRow("typenames in an import should be private to the import scope")
3210 << testFileUrl("jsimportfail/failFour.qml")
3212 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3213 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3214 << (QVariantList() << QVariant(0));
3216 QTest::newRow("import with imports has it's own activation scope")
3217 << testFileUrl("jsimportfail/failFive.qml")
3219 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component")))
3220 << (QStringList() << QLatin1String("componentError"))
3221 << (QVariantList() << QVariant(0));
3223 QTest::newRow("import pragma library script")
3224 << testFileUrl("jsimport/testImportPragmaLibrary.qml")
3227 << (QStringList() << QLatin1String("testValue"))
3228 << (QVariantList() << QVariant(31));
3230 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3231 << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
3233 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3234 << (QStringList() << QLatin1String("testValue"))
3235 << (QVariantList() << QVariant(0));
3237 QTest::newRow("import pragma library script which has an import")
3238 << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
3241 << (QStringList() << QLatin1String("testValue"))
3242 << (QVariantList() << QVariant(55));
3244 QTest::newRow("import pragma library script which has a pragma library import")
3245 << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3248 << (QStringList() << QLatin1String("testValue"))
3249 << (QVariantList() << QVariant(18));
3252 void tst_qdeclarativeecmascript::importScripts()
3254 QFETCH(QUrl, testfile);
3255 QFETCH(QString, errorMessage);
3256 QFETCH(QStringList, warningMessages);
3257 QFETCH(QStringList, propertyNames);
3258 QFETCH(QVariantList, propertyValues);
3260 QDeclarativeComponent component(&engine, testfile);
3262 if (!errorMessage.isEmpty())
3263 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3265 if (warningMessages.size())
3266 foreach (const QString &warning, warningMessages)
3267 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3269 QObject *object = component.create();
3270 if (!errorMessage.isEmpty()) {
3271 QVERIFY(object == 0);
3273 QVERIFY(object != 0);
3274 for (int i = 0; i < propertyNames.size(); ++i)
3275 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3280 void tst_qdeclarativeecmascript::scarceResources_other()
3282 /* These tests require knowledge of state, since we test values after
3283 performing signal or function invocation. */
3285 QPixmap origPixmap(100, 100);
3286 origPixmap.fill(Qt::blue);
3287 QString srp_name, expectedWarning;
3288 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3289 ScarceResourceObject *eo = 0;
3291 QObject *object = 0;
3293 /* property var semantics */
3295 // test that scarce resources are handled properly in signal invocation
3296 QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
3297 object = varComponentTen.create();
3298 srsc = object->findChild<QObject*>("srsc");
3300 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3301 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3302 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3303 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3304 QMetaObject::invokeMethod(srsc, "testSignal");
3305 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3306 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3307 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3308 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3309 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3310 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3311 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3312 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3313 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3314 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3317 // test that scarce resources are handled properly from js functions in qml files
3318 QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
3319 object = varComponentEleven.create();
3320 QVERIFY(object != 0);
3321 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3322 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3323 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3324 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3325 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3326 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3327 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3328 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3329 QMetaObject::invokeMethod(object, "releaseScarceResource");
3330 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3331 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3332 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3333 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3336 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3337 QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
3338 object = varComponentTwelve.create();
3339 QVERIFY(object != 0);
3340 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3341 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3342 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3343 srp_name = object->property("srp_name").toString();
3344 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3345 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3346 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3347 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3348 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3349 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3350 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3353 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3354 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3355 QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
3356 object = varComponentThirteen.create();
3357 QVERIFY(object != 0);
3358 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3359 QMetaObject::invokeMethod(object, "assignVarProperty");
3360 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3361 QMetaObject::invokeMethod(object, "deassignVarProperty");
3362 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3365 /* property variant semantics */
3367 // test that scarce resources are handled properly in signal invocation
3368 QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
3369 object = variantComponentTen.create();
3370 QVERIFY(object != 0);
3371 srsc = object->findChild<QObject*>("srsc");
3373 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3374 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3375 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3376 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3377 QMetaObject::invokeMethod(srsc, "testSignal");
3378 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3379 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3380 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3381 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3382 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3383 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3384 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3385 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3386 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3387 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3390 // test that scarce resources are handled properly from js functions in qml files
3391 QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
3392 object = variantComponentEleven.create();
3393 QVERIFY(object != 0);
3394 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3395 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3396 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3397 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3398 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3399 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3400 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3401 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3402 QMetaObject::invokeMethod(object, "releaseScarceResource");
3403 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3404 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3405 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3406 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3409 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3410 QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
3411 object = variantComponentTwelve.create();
3412 QVERIFY(object != 0);
3413 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3414 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3415 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3416 srp_name = object->property("srp_name").toString();
3417 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3418 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3419 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3420 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3421 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3422 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3423 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3427 void tst_qdeclarativeecmascript::scarceResources_data()
3429 QTest::addColumn<QUrl>("qmlFile");
3430 QTest::addColumn<bool>("readDetachStatus");
3431 QTest::addColumn<bool>("expectedDetachStatus");
3432 QTest::addColumn<QStringList>("propertyNames");
3433 QTest::addColumn<QVariantList>("expectedValidity");
3434 QTest::addColumn<QVariantList>("expectedValues");
3435 QTest::addColumn<QStringList>("expectedErrors");
3437 QPixmap origPixmap(100, 100);
3438 origPixmap.fill(Qt::blue);
3440 /* property var semantics */
3442 // in the following three cases, the instance created from the component
3443 // has a property which is a copy of the scarce resource; hence, the
3444 // resource should NOT be detached prior to deletion of the object instance,
3445 // unless the resource is destroyed explicitly.
3446 QTest::newRow("var: import scarce resource copy directly")
3447 << testFileUrl("scarceResourceCopy.var.qml")
3449 << false // won't be detached, because assigned to property and not explicitly released
3450 << (QStringList() << QLatin1String("scarceResourceCopy"))
3451 << (QList<QVariant>() << true)
3452 << (QList<QVariant>() << origPixmap)
3455 QTest::newRow("var: import scarce resource copy from JS")
3456 << testFileUrl("scarceResourceCopyFromJs.var.qml")
3458 << false // won't be detached, because assigned to property and not explicitly released
3459 << (QStringList() << QLatin1String("scarceResourceCopy"))
3460 << (QList<QVariant>() << true)
3461 << (QList<QVariant>() << origPixmap)
3464 QTest::newRow("var: import released scarce resource copy from JS")
3465 << testFileUrl("scarceResourceDestroyedCopy.var.qml")
3467 << true // explicitly released, so it will be detached
3468 << (QStringList() << QLatin1String("scarceResourceCopy"))
3469 << (QList<QVariant>() << false)
3470 << (QList<QVariant>() << QVariant())
3473 // in the following three cases, no other copy should exist in memory,
3474 // and so it should be detached (unless explicitly preserved).
3475 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3476 << testFileUrl("scarceResourceTest.var.qml")
3478 << true // auto released, so it will be detached
3479 << (QStringList() << QLatin1String("scarceResourceTest"))
3480 << (QList<QVariant>() << true)
3481 << (QList<QVariant>() << QVariant(100))
3483 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3484 << testFileUrl("scarceResourceTestPreserve.var.qml")
3486 << false // won't be detached because we explicitly preserve it
3487 << (QStringList() << QLatin1String("scarceResourceTest"))
3488 << (QList<QVariant>() << true)
3489 << (QList<QVariant>() << QVariant(100))
3491 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3492 << testFileUrl("scarceResourceTestMultiple.var.qml")
3494 << true // will be detached because all resources were released manually or automatically.
3495 << (QStringList() << QLatin1String("scarceResourceTest"))
3496 << (QList<QVariant>() << true)
3497 << (QList<QVariant>() << QVariant(100))
3500 // In the following three cases, test that scarce resources are handled
3501 // correctly for imports.
3502 QTest::newRow("var: import with no binding")
3503 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3504 << false // cannot check detach status.
3507 << QList<QVariant>()
3508 << QList<QVariant>()
3510 QTest::newRow("var: import with binding without explicit preserve")
3511 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3514 << (QStringList() << QLatin1String("scarceResourceCopy"))
3515 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3516 << (QList<QVariant>() << QVariant())
3518 QTest::newRow("var: import with explicit release after binding evaluation")
3519 << testFileUrl("scarceResourceCopyImport.var.qml")
3522 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3523 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3524 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3526 QTest::newRow("var: import with different js objects")
3527 << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
3530 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3531 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3532 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3534 QTest::newRow("var: import with different js objects and explicit release")
3535 << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
3538 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3539 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3540 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3542 QTest::newRow("var: import with same js objects and explicit release")
3543 << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
3546 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3547 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3548 << (QList<QVariant>() << QVariant() << QVariant())
3550 QTest::newRow("var: binding with same js objects and explicit release")
3551 << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
3554 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3555 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3556 << (QList<QVariant>() << QVariant() << QVariant())
3560 /* property variant semantics */
3562 // in the following three cases, the instance created from the component
3563 // has a property which is a copy of the scarce resource; hence, the
3564 // resource should NOT be detached prior to deletion of the object instance,
3565 // unless the resource is destroyed explicitly.
3566 QTest::newRow("variant: import scarce resource copy directly")
3567 << testFileUrl("scarceResourceCopy.variant.qml")
3569 << false // won't be detached, because assigned to property and not explicitly released
3570 << (QStringList() << QLatin1String("scarceResourceCopy"))
3571 << (QList<QVariant>() << true)
3572 << (QList<QVariant>() << origPixmap)
3575 QTest::newRow("variant: import scarce resource copy from JS")
3576 << testFileUrl("scarceResourceCopyFromJs.variant.qml")
3578 << false // won't be detached, because assigned to property and not explicitly released
3579 << (QStringList() << QLatin1String("scarceResourceCopy"))
3580 << (QList<QVariant>() << true)
3581 << (QList<QVariant>() << origPixmap)
3584 QTest::newRow("variant: import released scarce resource copy from JS")
3585 << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
3587 << true // explicitly released, so it will be detached
3588 << (QStringList() << QLatin1String("scarceResourceCopy"))
3589 << (QList<QVariant>() << false)
3590 << (QList<QVariant>() << QVariant())
3593 // in the following three cases, no other copy should exist in memory,
3594 // and so it should be detached (unless explicitly preserved).
3595 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3596 << testFileUrl("scarceResourceTest.variant.qml")
3598 << true // auto released, so it will be detached
3599 << (QStringList() << QLatin1String("scarceResourceTest"))
3600 << (QList<QVariant>() << true)
3601 << (QList<QVariant>() << QVariant(100))
3603 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3604 << testFileUrl("scarceResourceTestPreserve.variant.qml")
3606 << false // won't be detached because we explicitly preserve it
3607 << (QStringList() << QLatin1String("scarceResourceTest"))
3608 << (QList<QVariant>() << true)
3609 << (QList<QVariant>() << QVariant(100))
3611 QTest::newRow("variant: import multiple scarce resources")
3612 << testFileUrl("scarceResourceTestMultiple.variant.qml")
3614 << true // will be detached because all resources were released manually or automatically.
3615 << (QStringList() << QLatin1String("scarceResourceTest"))
3616 << (QList<QVariant>() << true)
3617 << (QList<QVariant>() << QVariant(100))
3620 // In the following three cases, test that scarce resources are handled
3621 // correctly for imports.
3622 QTest::newRow("variant: import with no binding")
3623 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3624 << false // cannot check detach status.
3627 << QList<QVariant>()
3628 << QList<QVariant>()
3630 QTest::newRow("variant: import with binding without explicit preserve")
3631 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3634 << (QStringList() << QLatin1String("scarceResourceCopy"))
3635 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3636 << (QList<QVariant>() << QVariant())
3638 QTest::newRow("variant: import with explicit release after binding evaluation")
3639 << testFileUrl("scarceResourceCopyImport.variant.qml")
3642 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3643 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3644 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3648 void tst_qdeclarativeecmascript::scarceResources()
3650 QFETCH(QUrl, qmlFile);
3651 QFETCH(bool, readDetachStatus);
3652 QFETCH(bool, expectedDetachStatus);
3653 QFETCH(QStringList, propertyNames);
3654 QFETCH(QVariantList, expectedValidity);
3655 QFETCH(QVariantList, expectedValues);
3656 QFETCH(QStringList, expectedErrors);
3658 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3659 ScarceResourceObject *eo = 0;
3660 QObject *object = 0;
3662 QDeclarativeComponent c(&engine, qmlFile);
3663 object = c.create();
3664 QVERIFY(object != 0);
3665 for (int i = 0; i < propertyNames.size(); ++i) {
3666 QString prop = propertyNames.at(i);
3667 bool validity = expectedValidity.at(i).toBool();
3668 QVariant value = expectedValues.at(i);
3670 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3671 if (value.type() == QVariant::Int) {
3672 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3673 } else if (value.type() == QVariant::Pixmap) {
3674 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3678 if (readDetachStatus) {
3679 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3680 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3683 QVERIFY(ep->scarceResources.isEmpty());
3687 void tst_qdeclarativeecmascript::propertyChangeSlots()
3689 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3690 QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
3691 QObject *object = component.create();
3692 QVERIFY(object != 0);
3695 // ensure that invalid property names fail properly.
3696 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3697 QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
3698 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3699 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3700 object = e1.create();
3701 QVERIFY(object == 0);
3704 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3705 QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
3706 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3707 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3708 object = e2.create();
3709 QVERIFY(object == 0);
3712 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3713 QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
3714 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3715 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3716 object = e3.create();
3717 QVERIFY(object == 0);
3720 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3721 QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
3722 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3723 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3724 object = e4.create();
3725 QVERIFY(object == 0);
3729 void tst_qdeclarativeecmascript::propertyVar_data()
3731 QTest::addColumn<QUrl>("qmlFile");
3734 QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
3735 QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
3736 QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
3737 QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
3738 QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
3739 QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
3740 QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
3741 QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
3742 QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
3743 QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
3746 void tst_qdeclarativeecmascript::propertyVar()
3748 QFETCH(QUrl, qmlFile);
3750 QDeclarativeComponent component(&engine, qmlFile);
3751 QObject *object = component.create();
3752 QVERIFY(object != 0);
3754 QCOMPARE(object->property("test").toBool(), true);
3759 // Tests that we can write QVariant values to var properties from C++
3760 void tst_qdeclarativeecmascript::propertyVarCpp()
3762 QObject *object = 0;
3764 // ensure that writing to and reading from a var property from cpp works as required.
3765 // Literal values stored in var properties can be read and written as QVariants
3766 // of a specific type, whereas object values are read as QVariantMaps.
3767 QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
3768 object = component.create();
3769 QVERIFY(object != 0);
3770 // assign int to property var that currently has int assigned
3771 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3772 QCOMPARE(object->property("varBound"), QVariant(15));
3773 QCOMPARE(object->property("intBound"), QVariant(15));
3774 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3775 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3776 // assign string to property var that current has bool assigned
3777 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3778 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3779 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3780 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3781 // now enforce behaviour when accessing JavaScript objects from cpp.
3782 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3786 static void gc(QDeclarativeEngine &engine)
3788 engine.collectGarbage();
3789 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
3790 QCoreApplication::processEvents();
3793 void tst_qdeclarativeecmascript::propertyVarOwnership()
3795 // Referenced JS objects are not collected
3797 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
3798 QObject *object = component.create();
3799 QVERIFY(object != 0);
3800 QCOMPARE(object->property("test").toBool(), false);
3801 QMetaObject::invokeMethod(object, "runTest");
3802 QCOMPARE(object->property("test").toBool(), true);
3805 // Referenced JS objects are not collected
3807 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
3808 QObject *object = component.create();
3809 QVERIFY(object != 0);
3810 QCOMPARE(object->property("test").toBool(), false);
3811 QMetaObject::invokeMethod(object, "runTest");
3812 QCOMPARE(object->property("test").toBool(), true);
3815 // Qt objects are not collected until they've been dereferenced
3817 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
3818 QObject *object = component.create();
3819 QVERIFY(object != 0);
3821 QCOMPARE(object->property("test2").toBool(), false);
3822 QCOMPARE(object->property("test2").toBool(), false);
3824 QMetaObject::invokeMethod(object, "runTest");
3825 QCOMPARE(object->property("test1").toBool(), true);
3827 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3828 QVERIFY(!referencedObject.isNull());
3830 QVERIFY(!referencedObject.isNull());
3832 QMetaObject::invokeMethod(object, "runTest2");
3833 QCOMPARE(object->property("test2").toBool(), true);
3835 QVERIFY(referencedObject.isNull());
3839 // Self reference does not prevent Qt object collection
3841 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
3842 QObject *object = component.create();
3843 QVERIFY(object != 0);
3845 QCOMPARE(object->property("test").toBool(), true);
3847 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3848 QVERIFY(!referencedObject.isNull());
3850 QVERIFY(!referencedObject.isNull());
3852 QMetaObject::invokeMethod(object, "runTest");
3854 QVERIFY(referencedObject.isNull());
3860 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3862 // The childObject has a reference to a different QObject. We want to ensure
3863 // that the different item will not be cleaned up until required. IE, the childObject
3864 // has implicit ownership of the constructed QObject.
3865 QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
3866 QObject *object = component.create();
3867 QVERIFY(object != 0);
3868 QMetaObject::invokeMethod(object, "assignCircular");
3869 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3870 QCoreApplication::processEvents();
3871 QObject *rootObject = object->property("vp").value<QObject*>();
3872 QVERIFY(rootObject != 0);
3873 QObject *childObject = rootObject->findChild<QObject*>("text");
3874 QVERIFY(childObject != 0);
3875 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3876 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3877 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3878 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3879 QVERIFY(!qobjectGuard.isNull());
3880 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3881 QCoreApplication::processEvents();
3882 QVERIFY(!qobjectGuard.isNull());
3883 QMetaObject::invokeMethod(object, "deassignCircular");
3884 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3885 QCoreApplication::processEvents();
3886 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3890 void tst_qdeclarativeecmascript::propertyVarReparent()
3892 // ensure that nothing breaks if we re-parent objects
3893 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3894 QObject *object = component.create();
3895 QVERIFY(object != 0);
3896 QMetaObject::invokeMethod(object, "assignVarProp");
3897 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3898 QCoreApplication::processEvents();
3899 QObject *rect = object->property("vp").value<QObject*>();
3900 QObject *text = rect->findChild<QObject*>("textOne");
3901 QObject *text2 = rect->findChild<QObject*>("textTwo");
3902 QWeakPointer<QObject> rectGuard(rect);
3903 QWeakPointer<QObject> textGuard(text);
3904 QWeakPointer<QObject> text2Guard(text2);
3905 QVERIFY(!rectGuard.isNull());
3906 QVERIFY(!textGuard.isNull());
3907 QVERIFY(!text2Guard.isNull());
3908 QCOMPARE(text->property("textCanary").toInt(), 11);
3909 QCOMPARE(text2->property("textCanary").toInt(), 12);
3910 // now construct an image which we will reparent.
3911 QMetaObject::invokeMethod(text2, "constructQObject");
3912 QObject *image = text2->property("vp").value<QObject*>();
3913 QWeakPointer<QObject> imageGuard(image);
3914 QVERIFY(!imageGuard.isNull());
3915 QCOMPARE(image->property("imageCanary").toInt(), 13);
3916 // now reparent the "Image" object (currently, it has JS ownership)
3917 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3918 QMetaObject::invokeMethod(text2, "deassignVp");
3919 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3920 QCoreApplication::processEvents();
3921 QCOMPARE(text->property("textCanary").toInt(), 11);
3922 QCOMPARE(text2->property("textCanary").toInt(), 22);
3923 QVERIFY(!imageGuard.isNull()); // should still be alive.
3924 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3925 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3926 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3927 QCoreApplication::processEvents();
3928 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3932 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3934 // sometimes reparenting can cause problems
3935 // (eg, if the ctxt is collected, varproperties are no longer available)
3936 // this test ensures that no crash occurs in that situation.
3937 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3938 QObject *object = component.create();
3939 QVERIFY(object != 0);
3940 QMetaObject::invokeMethod(object, "assignVarProp");
3941 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3942 QCoreApplication::processEvents();
3943 QObject *rect = object->property("vp").value<QObject*>();
3944 QObject *text = rect->findChild<QObject*>("textOne");
3945 QObject *text2 = rect->findChild<QObject*>("textTwo");
3946 QWeakPointer<QObject> rectGuard(rect);
3947 QWeakPointer<QObject> textGuard(text);
3948 QWeakPointer<QObject> text2Guard(text2);
3949 QVERIFY(!rectGuard.isNull());
3950 QVERIFY(!textGuard.isNull());
3951 QVERIFY(!text2Guard.isNull());
3952 QCOMPARE(text->property("textCanary").toInt(), 11);
3953 QCOMPARE(text2->property("textCanary").toInt(), 12);
3954 // now construct an image which we will reparent.
3955 QMetaObject::invokeMethod(text2, "constructQObject");
3956 QObject *image = text2->property("vp").value<QObject*>();
3957 QWeakPointer<QObject> imageGuard(image);
3958 QVERIFY(!imageGuard.isNull());
3959 QCOMPARE(image->property("imageCanary").toInt(), 13);
3960 // now reparent the "Image" object (currently, it has JS ownership)
3961 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3962 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3963 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3964 QCoreApplication::processEvents();
3965 QVERIFY(!imageGuard.isNull()); // should still be alive.
3966 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3968 QVERIFY(imageGuard.isNull()); // should now be dead.
3971 void tst_qdeclarativeecmascript::propertyVarCircular()
3973 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3974 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
3975 QObject *object = component.create();
3976 QVERIFY(object != 0);
3977 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3978 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3979 QCoreApplication::processEvents();
3980 QCOMPARE(object->property("canaryInt"), QVariant(5));
3981 QVariant canaryResourceVariant = object->property("canaryResource");
3982 QVERIFY(canaryResourceVariant.isValid());
3983 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3984 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3985 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3986 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3987 QCoreApplication::processEvents();
3988 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3989 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3990 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3991 QCoreApplication::processEvents();
3992 QCOMPARE(object->property("canaryInt"), QVariant(2));
3993 QCOMPARE(object->property("canaryResource"), QVariant(1));
3994 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3998 void tst_qdeclarativeecmascript::propertyVarCircular2()
4000 // track deletion of JS-owned parent item with Cpp-owned child
4001 // where the child has a var property referencing its parent.
4002 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4003 QObject *object = component.create();
4004 QVERIFY(object != 0);
4005 QMetaObject::invokeMethod(object, "assignCircular");
4006 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4007 QCoreApplication::processEvents();
4008 QObject *rootObject = object->property("vp").value<QObject*>();
4009 QVERIFY(rootObject != 0);
4010 QObject *childObject = rootObject->findChild<QObject*>("text");
4011 QVERIFY(childObject != 0);
4012 QWeakPointer<QObject> rootObjectTracker(rootObject);
4013 QVERIFY(!rootObjectTracker.isNull());
4014 QWeakPointer<QObject> childObjectTracker(childObject);
4015 QVERIFY(!childObjectTracker.isNull());
4017 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4018 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4019 QMetaObject::invokeMethod(object, "deassignCircular");
4020 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4021 QCoreApplication::processEvents();
4022 QVERIFY(rootObjectTracker.isNull()); // should have been collected
4023 QVERIFY(childObjectTracker.isNull()); // should have been collected
4027 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
4029 *(int*)(parameter) += 1;
4030 qPersistentDispose(object);
4033 void tst_qdeclarativeecmascript::propertyVarInheritance()
4035 int propertyVarWeakRefCallbackCount = 0;
4037 // enforce behaviour regarding element inheritance - ensure handle disposal.
4038 // The particular component under test here has a chain of references.
4039 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
4040 QObject *object = component.create();
4041 QVERIFY(object != 0);
4042 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
4043 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4044 QCoreApplication::processEvents();
4045 // we want to be able to track when the varProperties array of the last metaobject is disposed
4046 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
4047 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*>();
4048 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
4049 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
4050 v8::Persistent<v8::Value> icoCanaryHandle;
4051 v8::Persistent<v8::Value> ccoCanaryHandle;
4054 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4055 // public function which can return us a handle to something in the varProperties array.
4056 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4057 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4058 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4059 // as the varproperties array of each vmemo still references the resource.
4060 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4061 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4063 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4065 // now we deassign the var prop, which should trigger collection of item subtrees.
4066 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4067 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4068 QCoreApplication::processEvents();
4069 // ensure that there are only weak handles to the underlying varProperties array remaining.
4071 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4073 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4074 // to what remains are weak, all varProperties arrays must have been collected.
4077 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4079 int propertyVarWeakRefCallbackCount = 0;
4081 // The particular component under test here does NOT have a chain of references; the
4082 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4083 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4084 QObject *object = component.create();
4085 QVERIFY(object != 0);
4086 QMetaObject::invokeMethod(object, "assignCircular");
4087 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4088 QCoreApplication::processEvents();
4089 QObject *rootObject = object->property("vp").value<QObject*>();
4090 QVERIFY(rootObject != 0);
4091 QObject *childObject = rootObject->findChild<QObject*>("text");
4092 QVERIFY(childObject != 0);
4093 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4094 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4095 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4098 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4099 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
4100 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4102 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4103 QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
4104 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4106 QMetaObject::invokeMethod(object, "deassignCircular");
4107 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4108 QCoreApplication::processEvents();
4109 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4113 // Ensure that QObject type conversion works on binding assignment
4114 void tst_qdeclarativeecmascript::elementAssign()
4116 QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
4118 QObject *object = component.create();
4119 QVERIFY(object != 0);
4121 QCOMPARE(object->property("test").toBool(), true);
4127 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4129 QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
4131 QObject *object = component.create();
4132 QVERIFY(object != 0);
4134 QCOMPARE(object->property("test").toBool(), true);
4140 void tst_qdeclarativeecmascript::objectConversion()
4142 QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
4144 QObject *object = component.create();
4145 QVERIFY(object != 0);
4147 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4148 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4155 void tst_qdeclarativeecmascript::booleanConversion()
4157 QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
4159 QObject *object = component.create();
4160 QVERIFY(object != 0);
4162 QCOMPARE(object->property("test_true1").toBool(), true);
4163 QCOMPARE(object->property("test_true2").toBool(), true);
4164 QCOMPARE(object->property("test_true3").toBool(), true);
4165 QCOMPARE(object->property("test_true4").toBool(), true);
4166 QCOMPARE(object->property("test_true5").toBool(), true);
4168 QCOMPARE(object->property("test_false1").toBool(), false);
4169 QCOMPARE(object->property("test_false2").toBool(), false);
4170 QCOMPARE(object->property("test_false3").toBool(), false);
4175 void tst_qdeclarativeecmascript::handleReferenceManagement()
4180 // Linear QObject reference
4181 QDeclarativeEngine hrmEngine;
4182 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
4183 QObject *object = component.create();
4184 QVERIFY(object != 0);
4185 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4186 cro->setEngine(&hrmEngine);
4187 cro->setDtorCount(&dtorCount);
4188 QMetaObject::invokeMethod(object, "createReference");
4190 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4192 hrmEngine.collectGarbage();
4193 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4194 QCoreApplication::processEvents();
4195 QCOMPARE(dtorCount, 3);
4200 // Circular QObject reference
4201 QDeclarativeEngine hrmEngine;
4202 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
4203 QObject *object = component.create();
4204 QVERIFY(object != 0);
4205 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4206 cro->setEngine(&hrmEngine);
4207 cro->setDtorCount(&dtorCount);
4208 QMetaObject::invokeMethod(object, "circularReference");
4210 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4212 hrmEngine.collectGarbage();
4213 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4214 QCoreApplication::processEvents();
4215 QCOMPARE(dtorCount, 3);
4220 // Linear handle reference
4221 QDeclarativeEngine hrmEngine;
4222 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
4223 QObject *object = component.create();
4224 QVERIFY(object != 0);
4225 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4227 crh->setEngine(&hrmEngine);
4228 crh->setDtorCount(&dtorCount);
4229 QMetaObject::invokeMethod(object, "createReference");
4230 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4231 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4232 QVERIFY(first != 0);
4233 QVERIFY(second != 0);
4234 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4235 // now we have to reparent second and make second owned by JS.
4236 second->setParent(0);
4237 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4239 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4241 hrmEngine.collectGarbage();
4242 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4243 QCoreApplication::processEvents();
4244 QCOMPARE(dtorCount, 3);
4249 // Circular handle reference
4250 QDeclarativeEngine hrmEngine;
4251 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
4252 QObject *object = component.create();
4253 QVERIFY(object != 0);
4254 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4256 crh->setEngine(&hrmEngine);
4257 crh->setDtorCount(&dtorCount);
4258 QMetaObject::invokeMethod(object, "circularReference");
4259 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4260 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4261 QVERIFY(first != 0);
4262 QVERIFY(second != 0);
4263 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4264 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4265 // now we have to reparent and change ownership.
4266 first->setParent(0);
4267 second->setParent(0);
4268 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4269 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4271 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4273 hrmEngine.collectGarbage();
4274 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4275 QCoreApplication::processEvents();
4276 QCOMPARE(dtorCount, 3);
4281 // multiple engine interaction - linear reference
4282 QDeclarativeEngine hrmEngine1;
4283 QDeclarativeEngine hrmEngine2;
4284 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4285 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4286 QObject *object1 = component1.create();
4287 QObject *object2 = component2.create();
4288 QVERIFY(object1 != 0);
4289 QVERIFY(object2 != 0);
4290 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4291 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4294 crh1->setEngine(&hrmEngine1);
4295 crh2->setEngine(&hrmEngine2);
4296 crh1->setDtorCount(&dtorCount);
4297 crh2->setDtorCount(&dtorCount);
4298 QMetaObject::invokeMethod(object1, "createReference");
4299 QMetaObject::invokeMethod(object2, "createReference");
4300 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4301 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4302 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4303 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4304 QVERIFY(first1 != 0);
4305 QVERIFY(second1 != 0);
4306 QVERIFY(first2 != 0);
4307 QVERIFY(second2 != 0);
4308 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4309 // now we have to reparent second2 and make second2 owned by JS.
4310 second2->setParent(0);
4311 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4313 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4314 QCoreApplication::processEvents();
4315 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4318 hrmEngine1.collectGarbage();
4319 hrmEngine2.collectGarbage();
4320 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4321 QCoreApplication::processEvents();
4322 QCOMPARE(dtorCount, 6);
4327 // multiple engine interaction - circular reference
4328 QDeclarativeEngine hrmEngine1;
4329 QDeclarativeEngine hrmEngine2;
4330 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4331 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4332 QObject *object1 = component1.create();
4333 QObject *object2 = component2.create();
4334 QVERIFY(object1 != 0);
4335 QVERIFY(object2 != 0);
4336 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4337 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4340 crh1->setEngine(&hrmEngine1);
4341 crh2->setEngine(&hrmEngine2);
4342 crh1->setDtorCount(&dtorCount);
4343 crh2->setDtorCount(&dtorCount);
4344 QMetaObject::invokeMethod(object1, "createReference");
4345 QMetaObject::invokeMethod(object2, "createReference");
4346 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4347 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4348 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4349 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4350 QVERIFY(first1 != 0);
4351 QVERIFY(second1 != 0);
4352 QVERIFY(first2 != 0);
4353 QVERIFY(second2 != 0);
4354 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4355 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4356 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4357 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4358 // now we have to reparent and change ownership to JS.
4359 first1->setParent(0);
4360 second1->setParent(0);
4361 first2->setParent(0);
4362 second2->setParent(0);
4363 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4364 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4365 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4366 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4368 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4369 QCoreApplication::processEvents();
4370 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4373 hrmEngine1.collectGarbage();
4374 hrmEngine2.collectGarbage();
4375 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4376 QCoreApplication::processEvents();
4377 QCOMPARE(dtorCount, 6);
4382 // multiple engine interaction - linear reference with engine deletion
4383 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4384 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4385 QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4386 QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4387 QObject *object1 = component1.create();
4388 QObject *object2 = component2.create();
4389 QVERIFY(object1 != 0);
4390 QVERIFY(object2 != 0);
4391 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4392 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4395 crh1->setEngine(hrmEngine1);
4396 crh2->setEngine(hrmEngine2);
4397 crh1->setDtorCount(&dtorCount);
4398 crh2->setDtorCount(&dtorCount);
4399 QMetaObject::invokeMethod(object1, "createReference");
4400 QMetaObject::invokeMethod(object2, "createReference");
4401 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4402 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4403 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4404 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4405 QVERIFY(first1 != 0);
4406 QVERIFY(second1 != 0);
4407 QVERIFY(first2 != 0);
4408 QVERIFY(second2 != 0);
4409 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4410 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4411 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4412 // now we have to reparent and change ownership to JS.
4413 first1->setParent(crh1);
4414 second1->setParent(0);
4415 first2->setParent(0);
4416 second2->setParent(0);
4417 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4418 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4419 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4421 QCOMPARE(dtorCount, 0);
4424 QCOMPARE(dtorCount, 0);
4427 hrmEngine1->collectGarbage();
4428 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4429 QCoreApplication::processEvents();
4430 QCOMPARE(dtorCount, 6);
4435 void tst_qdeclarativeecmascript::stringArg()
4437 QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
4438 QObject *object = component.create();
4439 QVERIFY(object != 0);
4440 QMetaObject::invokeMethod(object, "success");
4441 QVERIFY(object->property("returnValue").toBool());
4443 QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4444 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4445 QMetaObject::invokeMethod(object, "failure");
4446 QVERIFY(object->property("returnValue").toBool());
4451 void tst_qdeclarativeecmascript::readonlyDeclaration()
4453 QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
4455 QObject *object = component.create();
4456 QVERIFY(object != 0);
4458 QCOMPARE(object->property("test").toBool(), true);
4463 Q_DECLARE_METATYPE(QList<int>)
4464 Q_DECLARE_METATYPE(QList<qreal>)
4465 Q_DECLARE_METATYPE(QList<bool>)
4466 Q_DECLARE_METATYPE(QList<QString>)
4467 Q_DECLARE_METATYPE(QList<QUrl>)
4468 void tst_qdeclarativeecmascript::sequenceConversionRead()
4471 QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
4472 QDeclarativeComponent component(&engine, qmlFile);
4473 QObject *object = component.create();
4474 QVERIFY(object != 0);
4475 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4478 QMetaObject::invokeMethod(object, "readSequences");
4479 QList<int> intList; intList << 1 << 2 << 3 << 4;
4480 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4481 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4482 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4483 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4484 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4485 QList<bool> boolList; boolList << true << false << true << false;
4486 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4487 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4488 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4489 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4490 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4491 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4492 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4493 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4494 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4495 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4496 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4498 QMetaObject::invokeMethod(object, "readSequenceElements");
4499 QCOMPARE(object->property("intVal").toInt(), 2);
4500 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4501 QCOMPARE(object->property("boolVal").toBool(), false);
4502 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4503 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4504 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4506 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4507 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4509 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4510 QDeclarativeProperty seqProp(seq, "intListProperty");
4511 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4512 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4513 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4515 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4516 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4522 QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
4523 QDeclarativeComponent component(&engine, qmlFile);
4524 QObject *object = component.create();
4525 QVERIFY(object != 0);
4526 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4529 // we haven't registered QList<QPoint> as a sequence type.
4530 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4531 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4532 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4533 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4535 QMetaObject::invokeMethod(object, "performTest");
4537 // QList<QPoint> has not been registered as a sequence type.
4538 QCOMPARE(object->property("pointListLength").toInt(), 0);
4539 QVERIFY(!object->property("pointList").isValid());
4540 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4541 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4542 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4548 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4551 QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
4552 QDeclarativeComponent component(&engine, qmlFile);
4553 QObject *object = component.create();
4554 QVERIFY(object != 0);
4555 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4558 QMetaObject::invokeMethod(object, "writeSequences");
4559 QCOMPARE(object->property("success").toBool(), true);
4561 QMetaObject::invokeMethod(object, "writeSequenceElements");
4562 QCOMPARE(object->property("success").toBool(), true);
4564 QMetaObject::invokeMethod(object, "writeOtherElements");
4565 QCOMPARE(object->property("success").toBool(), true);
4567 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4568 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4574 QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
4575 QDeclarativeComponent component(&engine, qmlFile);
4576 QObject *object = component.create();
4577 QVERIFY(object != 0);
4578 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4581 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4582 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4583 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4585 QMetaObject::invokeMethod(object, "performTest");
4587 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4588 QCOMPARE(seq->pointListProperty(), pointList);
4594 void tst_qdeclarativeecmascript::sequenceConversionArray()
4596 // ensure that in JS the returned sequences act just like normal JS Arrays.
4597 QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
4598 QDeclarativeComponent component(&engine, qmlFile);
4599 QObject *object = component.create();
4600 QVERIFY(object != 0);
4601 QMetaObject::invokeMethod(object, "indexedAccess");
4602 QVERIFY(object->property("success").toBool());
4603 QMetaObject::invokeMethod(object, "arrayOperations");
4604 QVERIFY(object->property("success").toBool());
4605 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4606 QVERIFY(object->property("success").toBool());
4607 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4608 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4613 void tst_qdeclarativeecmascript::sequenceConversionIndexes()
4615 // ensure that we gracefully fail if unsupported index values are specified.
4616 // Qt container classes only support non-negative, signed integer index values.
4617 QUrl qmlFile = testFileUrl("sequenceConversion.indexes.qml");
4618 QDeclarativeComponent component(&engine, qmlFile);
4619 QObject *object = component.create();
4620 QVERIFY(object != 0);
4621 QString w1 = qmlFile.toString() + QLatin1String(":34: Index out of range during length set");
4622 QString w2 = qmlFile.toString() + QLatin1String(":41: Index out of range during indexed set");
4623 QString w3 = qmlFile.toString() + QLatin1String(":48: Index out of range during indexed get");
4624 QString w4 = qmlFile.toString() + QLatin1String(":78: std::bad_alloc during length set");
4625 QString w5 = qmlFile.toString() + QLatin1String(":83: std::bad_alloc during indexed set");
4626 QTest::ignoreMessage(QtWarningMsg, qPrintable(w1));
4627 QTest::ignoreMessage(QtWarningMsg, qPrintable(w2));
4628 QTest::ignoreMessage(QtWarningMsg, qPrintable(w3));
4629 QTest::ignoreMessage(QtWarningMsg, qPrintable(w4));
4630 QTest::ignoreMessage(QtWarningMsg, qPrintable(w5));
4631 QMetaObject::invokeMethod(object, "indexedAccess");
4632 QVERIFY(object->property("success").toBool());
4636 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4638 // ensure that sequence conversion operations work correctly in a worker thread
4639 // and that serialisation between the main and worker thread succeeds.
4640 QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
4641 QDeclarativeComponent component(&engine, qmlFile);
4642 QObject *object = component.create();
4643 QVERIFY(object != 0);
4645 QMetaObject::invokeMethod(object, "testIntSequence");
4646 QTRY_VERIFY(object->property("finished").toBool());
4647 QVERIFY(object->property("success").toBool());
4649 QMetaObject::invokeMethod(object, "testQrealSequence");
4650 QTRY_VERIFY(object->property("finished").toBool());
4651 QVERIFY(object->property("success").toBool());
4653 QMetaObject::invokeMethod(object, "testBoolSequence");
4654 QTRY_VERIFY(object->property("finished").toBool());
4655 QVERIFY(object->property("success").toBool());
4657 QMetaObject::invokeMethod(object, "testStringSequence");
4658 QTRY_VERIFY(object->property("finished").toBool());
4659 QVERIFY(object->property("success").toBool());
4661 QMetaObject::invokeMethod(object, "testQStringSequence");
4662 QTRY_VERIFY(object->property("finished").toBool());
4663 QVERIFY(object->property("success").toBool());
4665 QMetaObject::invokeMethod(object, "testUrlSequence");
4666 QTRY_VERIFY(object->property("finished").toBool());
4667 QVERIFY(object->property("success").toBool());
4669 QMetaObject::invokeMethod(object, "testVariantSequence");
4670 QTRY_VERIFY(object->property("finished").toBool());
4671 QVERIFY(object->property("success").toBool());
4676 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4679 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
4680 QDeclarativeComponent component(&engine, qmlFile);
4681 QObject *object = component.create();
4682 QVERIFY(object != 0);
4683 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4684 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4685 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4686 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4687 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4692 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
4693 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4694 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4695 QDeclarativeComponent component(&engine, qmlFile);
4696 QObject *object = component.create();
4697 QVERIFY(object != 0);
4702 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4704 QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
4705 QDeclarativeComponent component(&engine, qmlFile);
4706 QObject *object = component.create();
4707 QVERIFY(object != 0);
4708 QMetaObject::invokeMethod(object, "testCopySequences");
4709 QCOMPARE(object->property("success").toBool(), true);
4710 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4711 QCOMPARE(object->property("success").toBool(), true);
4712 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4713 QCOMPARE(object->property("success").toBool(), true);
4717 void tst_qdeclarativeecmascript::assignSequenceTypes()
4719 // test binding array to sequence type property
4721 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
4722 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4723 QVERIFY(object != 0);
4724 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4725 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4726 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4727 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4728 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4729 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4733 // test binding literal to sequence type property
4735 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
4736 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4737 QVERIFY(object != 0);
4738 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4739 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4740 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4741 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4742 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4743 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4747 // test binding single value to sequence type property
4749 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
4750 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4751 QVERIFY(object != 0);
4752 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4753 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4754 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4755 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4759 // test assigning array to sequence type property in js function
4761 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
4762 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4763 QVERIFY(object != 0);
4764 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4765 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4766 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4767 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4768 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4769 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4773 // test assigning literal to sequence type property in js function
4775 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
4776 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4777 QVERIFY(object != 0);
4778 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4779 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4780 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4781 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4782 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4783 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4787 // test assigning single value to sequence type property in js function
4789 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
4790 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4791 QVERIFY(object != 0);
4792 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4793 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4794 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4795 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4799 // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
4801 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
4802 QObject *object = component.create();
4803 QVERIFY(object != 0);
4804 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
4805 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
4806 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
4807 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
4808 MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
4809 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
4810 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4811 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4812 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4813 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4814 QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4819 // Test that assigning a null object works
4820 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4821 void tst_qdeclarativeecmascript::nullObjectBinding()
4823 QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
4825 QObject *object = component.create();
4826 QVERIFY(object != 0);
4828 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4833 // Test that bindings don't evaluate once the engine has been destroyed
4834 void tst_qdeclarativeecmascript::deletedEngine()
4836 QDeclarativeEngine *engine = new QDeclarativeEngine;
4837 QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
4839 QObject *object = component.create();
4840 QVERIFY(object != 0);
4842 QCOMPARE(object->property("a").toInt(), 39);
4843 object->setProperty("b", QVariant(9));
4844 QCOMPARE(object->property("a").toInt(), 117);
4848 QCOMPARE(object->property("a").toInt(), 117);
4849 object->setProperty("b", QVariant(10));
4850 QCOMPARE(object->property("a").toInt(), 117);
4855 // Test the crashing part of QTBUG-9705
4856 void tst_qdeclarativeecmascript::libraryScriptAssert()
4858 QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
4860 QObject *object = component.create();
4861 QVERIFY(object != 0);
4866 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4868 QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
4870 QObject *object = component.create();
4871 QVERIFY(object != 0);
4873 QCOMPARE(object->property("test1").toInt(), 10);
4874 QCOMPARE(object->property("test2").toInt(), 11);
4876 object->setProperty("runTest", true);
4878 QCOMPARE(object->property("test1"), QVariant());
4879 QCOMPARE(object->property("test2"), QVariant());
4885 void tst_qdeclarativeecmascript::qtbug_9792()
4887 QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
4889 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4891 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4892 QVERIFY(object != 0);
4894 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4895 object->basicSignal();
4899 transientErrorsMsgCount = 0;
4900 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4902 object->basicSignal();
4904 qInstallMsgHandler(old);
4906 QCOMPARE(transientErrorsMsgCount, 0);
4911 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4912 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4914 QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
4916 QObject *o = component.create();
4919 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4920 QVERIFY(nested != 0);
4922 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4925 nested = qvariant_cast<QObject *>(o->property("object"));
4926 QVERIFY(nested == 0);
4928 // If the bug is present, the next line will crash
4932 // Test that we shut down without stupid warnings
4933 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4936 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
4938 QObject *o = component.create();
4940 transientErrorsMsgCount = 0;
4941 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4945 qInstallMsgHandler(old);
4947 QCOMPARE(transientErrorsMsgCount, 0);
4952 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
4954 QObject *o = component.create();
4956 transientErrorsMsgCount = 0;
4957 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4961 qInstallMsgHandler(old);
4963 QCOMPARE(transientErrorsMsgCount, 0);
4967 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4970 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
4972 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4975 QVERIFY(o->objectProperty() != 0);
4977 o->setProperty("runTest", true);
4979 QVERIFY(o->objectProperty() == 0);
4985 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
4987 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4990 QVERIFY(o->objectProperty() == 0);
4996 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4998 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
5000 QString url = component.url().toString();
5001 QString warning = url + ":4: Unable to assign a function to a property.";
5002 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5004 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5007 QVERIFY(!o->property("a").isValid());
5012 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
5014 QFETCH(QString, triggerProperty);
5016 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
5017 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
5019 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5021 QVERIFY(!o->property("a").isValid());
5023 o->setProperty("aNumber", QVariant(5));
5024 o->setProperty(triggerProperty.toUtf8().constData(), true);
5025 QCOMPARE(o->property("a"), QVariant(50));
5027 o->setProperty("aNumber", QVariant(10));
5028 QCOMPARE(o->property("a"), QVariant(100));
5033 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
5035 QTest::addColumn<QString>("triggerProperty");
5037 QTest::newRow("assign to property") << "assignToProperty";
5038 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
5040 QTest::newRow("assign to value type") << "assignToValueType";
5042 QTest::newRow("use 'this'") << "assignWithThis";
5043 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
5046 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
5048 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
5049 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
5051 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5053 QVERIFY(!o->property("a").isValid());
5055 o->setProperty("assignFuncWithoutReturn", true);
5056 QVERIFY(!o->property("a").isValid());
5058 QString url = component.url().toString();
5059 QString warning = url + ":67: Unable to assign QString to int";
5060 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5061 o->setProperty("assignWrongType", true);
5063 warning = url + ":71: Unable to assign QString to int";
5064 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5065 o->setProperty("assignWrongTypeToValueType", true);
5070 void tst_qdeclarativeecmascript::eval()
5072 QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
5074 QObject *o = component.create();
5077 QCOMPARE(o->property("test1").toBool(), true);
5078 QCOMPARE(o->property("test2").toBool(), true);
5079 QCOMPARE(o->property("test3").toBool(), true);
5080 QCOMPARE(o->property("test4").toBool(), true);
5081 QCOMPARE(o->property("test5").toBool(), true);
5086 void tst_qdeclarativeecmascript::function()
5088 QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
5090 QObject *o = component.create();
5093 QCOMPARE(o->property("test1").toBool(), true);
5094 QCOMPARE(o->property("test2").toBool(), true);
5095 QCOMPARE(o->property("test3").toBool(), true);
5100 void tst_qdeclarativeecmascript::functionException()
5102 // QTBUG-24037 - shouldn't crash.
5103 QString errstr = testFileUrl("v8functionException.qml").toString() + QLatin1String(":13: SyntaxError: Unexpected token ILLEGAL");
5104 QTest::ignoreMessage(QtWarningMsg, qPrintable(errstr));
5105 QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Exception occurred during compilation of function: dynamicSlot()");
5106 QDeclarativeComponent component(&engine, testFileUrl("v8functionException.qml"));
5107 QObject *o = component.create();
5109 QMetaObject::invokeMethod(o, "dynamicSlot");
5113 // Test the "Qt.include" method
5114 void tst_qdeclarativeecmascript::include()
5116 // Non-library relative include
5118 QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
5119 QObject *o = component.create();
5122 QCOMPARE(o->property("test0").toInt(), 99);
5123 QCOMPARE(o->property("test1").toBool(), true);
5124 QCOMPARE(o->property("test2").toBool(), true);
5125 QCOMPARE(o->property("test2_1").toBool(), true);
5126 QCOMPARE(o->property("test3").toBool(), true);
5127 QCOMPARE(o->property("test3_1").toBool(), true);
5132 // Library relative include
5134 QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
5135 QObject *o = component.create();
5138 QCOMPARE(o->property("test0").toInt(), 99);
5139 QCOMPARE(o->property("test1").toBool(), true);
5140 QCOMPARE(o->property("test2").toBool(), true);
5141 QCOMPARE(o->property("test2_1").toBool(), true);
5142 QCOMPARE(o->property("test3").toBool(), true);
5143 QCOMPARE(o->property("test3_1").toBool(), true);
5150 QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
5151 QObject *o = component.create();
5154 QCOMPARE(o->property("test1").toBool(), true);
5155 QCOMPARE(o->property("test2").toBool(), true);
5156 QCOMPARE(o->property("test3").toBool(), true);
5157 QCOMPARE(o->property("test4").toBool(), true);
5158 QCOMPARE(o->property("test5").toBool(), true);
5159 QCOMPARE(o->property("test6").toBool(), true);
5164 // Including file with ".pragma library"
5166 QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
5167 QObject *o = component.create();
5169 QCOMPARE(o->property("test1").toInt(), 100);
5176 TestHTTPServer server(8111);
5177 QVERIFY(server.isValid());
5178 server.serveDirectory(dataDirectory());
5180 QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
5181 QObject *o = component.create();
5184 QTRY_VERIFY(o->property("done").toBool() == true);
5185 QTRY_VERIFY(o->property("done2").toBool() == true);
5187 QCOMPARE(o->property("test1").toBool(), true);
5188 QCOMPARE(o->property("test2").toBool(), true);
5189 QCOMPARE(o->property("test3").toBool(), true);
5190 QCOMPARE(o->property("test4").toBool(), true);
5191 QCOMPARE(o->property("test5").toBool(), true);
5193 QCOMPARE(o->property("test6").toBool(), true);
5194 QCOMPARE(o->property("test7").toBool(), true);
5195 QCOMPARE(o->property("test8").toBool(), true);
5196 QCOMPARE(o->property("test9").toBool(), true);
5197 QCOMPARE(o->property("test10").toBool(), true);
5204 TestHTTPServer server(8111);
5205 QVERIFY(server.isValid());
5206 server.serveDirectory(dataDirectory());
5208 QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
5209 QObject *o = component.create();
5212 QTRY_VERIFY(o->property("done").toBool() == true);
5214 QCOMPARE(o->property("test1").toBool(), true);
5215 QCOMPARE(o->property("test2").toBool(), true);
5216 QCOMPARE(o->property("test3").toBool(), true);
5222 void tst_qdeclarativeecmascript::signalHandlers()
5224 QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
5225 QObject *o = component.create();
5228 QVERIFY(o->property("count").toInt() == 0);
5229 QMetaObject::invokeMethod(o, "testSignalCall");
5230 QCOMPARE(o->property("count").toInt(), 1);
5232 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5233 QCOMPARE(o->property("count").toInt(), 1);
5234 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5236 QVERIFY(o->property("funcCount").toInt() == 0);
5237 QMetaObject::invokeMethod(o, "testSignalConnection");
5238 QCOMPARE(o->property("funcCount").toInt(), 1);
5240 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5241 QCOMPARE(o->property("funcCount").toInt(), 2);
5243 QMetaObject::invokeMethod(o, "testSignalDefined");
5244 QCOMPARE(o->property("definedResult").toBool(), true);
5246 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5247 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5252 void tst_qdeclarativeecmascript::qtbug_10696()
5254 QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
5255 QObject *o = component.create();
5260 void tst_qdeclarativeecmascript::qtbug_11606()
5262 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
5263 QObject *o = component.create();
5265 QCOMPARE(o->property("test").toBool(), true);
5269 void tst_qdeclarativeecmascript::qtbug_11600()
5271 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
5272 QObject *o = component.create();
5274 QCOMPARE(o->property("test").toBool(), true);
5278 void tst_qdeclarativeecmascript::qtbug_21864()
5280 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
5281 QObject *o = component.create();
5283 QCOMPARE(o->property("test").toBool(), true);
5287 void tst_qdeclarativeecmascript::rewriteMultiLineStrings()
5290 QDeclarativeComponent component(&engine, testFileUrl("rewriteMultiLineStrings.qml"));
5291 QObject *o = component.create();
5293 QTRY_COMPARE(o->property("test").toBool(), true);
5297 void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
5300 QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
5301 QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
5302 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5303 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5304 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5305 QObject *o = component.create();
5307 QCOMPARE(o->property("test").toBool(), true);
5311 // Reading and writing non-scriptable properties should fail
5312 void tst_qdeclarativeecmascript::nonscriptable()
5314 QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
5315 QObject *o = component.create();
5317 QCOMPARE(o->property("readOk").toBool(), true);
5318 QCOMPARE(o->property("writeOk").toBool(), true);
5322 // deleteLater() should not be callable from QML
5323 void tst_qdeclarativeecmascript::deleteLater()
5325 QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
5326 QObject *o = component.create();
5328 QCOMPARE(o->property("test").toBool(), true);
5332 void tst_qdeclarativeecmascript::in()
5334 QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
5335 QObject *o = component.create();
5337 QCOMPARE(o->property("test1").toBool(), true);
5338 QCOMPARE(o->property("test2").toBool(), true);
5342 void tst_qdeclarativeecmascript::typeOf()
5344 QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
5346 // These warnings should not happen once QTBUG-21864 is fixed
5347 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5348 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5350 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5351 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5353 QObject *o = component.create();
5356 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5357 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5358 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5359 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5360 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5361 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5362 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5363 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5364 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5365 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5370 void tst_qdeclarativeecmascript::sharedAttachedObject()
5372 QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
5373 QObject *o = component.create();
5375 QCOMPARE(o->property("test1").toBool(), true);
5376 QCOMPARE(o->property("test2").toBool(), true);
5381 void tst_qdeclarativeecmascript::objectName()
5383 QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
5384 QObject *o = component.create();
5387 QCOMPARE(o->property("test1").toString(), QString("hello"));
5388 QCOMPARE(o->property("test2").toString(), QString("ell"));
5390 o->setObjectName("world");
5392 QCOMPARE(o->property("test1").toString(), QString("world"));
5393 QCOMPARE(o->property("test2").toString(), QString("orl"));
5398 void tst_qdeclarativeecmascript::writeRemovesBinding()
5400 QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
5401 QObject *o = component.create();
5404 QCOMPARE(o->property("test").toBool(), true);
5409 // Test bindings assigned to alias properties actually assign to the alias' target
5410 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5412 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
5413 QObject *o = component.create();
5416 QCOMPARE(o->property("test").toBool(), true);
5421 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5422 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5425 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
5426 QObject *o = component.create();
5429 QCOMPARE(o->property("test").toBool(), true);
5435 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
5436 QObject *o = component.create();
5439 QCOMPARE(o->property("test").toBool(), true);
5445 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
5446 QObject *o = component.create();
5449 QCOMPARE(o->property("test").toBool(), true);
5455 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5456 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5459 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
5460 QObject *o = component.create();
5463 QCOMPARE(o->property("test").toBool(), true);
5469 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
5470 QObject *o = component.create();
5473 QCOMPARE(o->property("test").toBool(), true);
5479 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
5480 QObject *o = component.create();
5483 QCOMPARE(o->property("test").toBool(), true);
5489 // Allow an alais to a composite element
5491 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5493 QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
5495 QObject *object = component.create();
5496 QVERIFY(object != 0);
5501 void tst_qdeclarativeecmascript::qtbug_20344()
5503 QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
5505 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5506 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5508 QObject *object = component.create();
5509 QVERIFY(object != 0);
5514 void tst_qdeclarativeecmascript::revisionErrors()
5517 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
5518 QString url = component.url().toString();
5520 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5521 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5522 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5524 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5525 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5526 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5527 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5528 QVERIFY(object != 0);
5532 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
5533 QString url = component.url().toString();
5535 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5536 // method2, prop2 from MyRevisionedClass not available
5537 // method4, prop4 from MyRevisionedSubclass not available
5538 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5539 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5540 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5541 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5542 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5544 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5545 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5546 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5547 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5548 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5549 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5550 QVERIFY(object != 0);
5554 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
5555 QString url = component.url().toString();
5557 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5558 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5559 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5560 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5561 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5562 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5563 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5564 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5565 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5566 QVERIFY(object != 0);
5571 void tst_qdeclarativeecmascript::revision()
5574 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
5575 QString url = component.url().toString();
5577 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5578 QVERIFY(object != 0);
5582 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
5583 QString url = component.url().toString();
5585 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5586 QVERIFY(object != 0);
5590 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
5591 QString url = component.url().toString();
5593 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5594 QVERIFY(object != 0);
5597 // Test that non-root classes can resolve revisioned methods
5599 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
5601 QObject *object = component.create();
5602 QVERIFY(object != 0);
5603 QCOMPARE(object->property("test").toReal(), 11.);
5608 void tst_qdeclarativeecmascript::realToInt()
5610 QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
5611 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5612 QVERIFY(object != 0);
5614 QMetaObject::invokeMethod(object, "test1");
5615 QCOMPARE(object->value(), int(4));
5616 QMetaObject::invokeMethod(object, "test2");
5617 QCOMPARE(object->value(), int(8));
5620 void tst_qdeclarativeecmascript::urlProperty()
5623 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
5624 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5625 QVERIFY(object != 0);
5626 object->setStringProperty("http://qt-project.org");
5627 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5628 QCOMPARE(object->intProperty(), 123);
5629 QCOMPARE(object->value(), 1);
5630 QCOMPARE(object->property("result").toBool(), true);
5634 void tst_qdeclarativeecmascript::urlPropertyWithEncoding()
5637 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.2.qml"));
5638 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5639 QVERIFY(object != 0);
5640 object->setStringProperty("http://qt-project.org");
5642 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5643 QCOMPARE(object->urlProperty(), encoded);
5644 QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
5645 QCOMPARE(object->property("result").toBool(), true);
5649 void tst_qdeclarativeecmascript::urlListPropertyWithEncoding()
5652 QDeclarativeComponent component(&engine, testFileUrl("urlListProperty.qml"));
5653 QObject *object = component.create();
5654 QVERIFY(object != 0);
5655 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
5656 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
5657 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
5658 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
5659 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
5661 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5662 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
5663 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
5664 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5665 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5670 void tst_qdeclarativeecmascript::dynamicString()
5672 QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
5673 QObject *object = component.create();
5674 QVERIFY(object != 0);
5675 QCOMPARE(object->property("stringProperty").toString(),
5676 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5679 void tst_qdeclarativeecmascript::automaticSemicolon()
5681 QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
5682 QObject *object = component.create();
5683 QVERIFY(object != 0);
5686 void tst_qdeclarativeecmascript::unaryExpression()
5688 QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
5689 QObject *object = component.create();
5690 QVERIFY(object != 0);
5693 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5694 void tst_qdeclarativeecmascript::doubleEvaluate()
5696 QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
5697 QObject *object = component.create();
5698 QVERIFY(object != 0);
5699 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5701 QCOMPARE(wc->count(), 1);
5703 wc->setProperty("x", 9);
5705 QCOMPARE(wc->count(), 2);
5710 static QStringList messages;
5711 static void captureMsgHandler(QtMsgType, const char *msg)
5713 messages.append(QLatin1String(msg));
5716 void tst_qdeclarativeecmascript::nonNotifyable()
5718 QV4Compiler::enableV4(false);
5719 QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
5720 QV4Compiler::enableV4(true);
5722 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5724 QObject *object = component.create();
5725 qInstallMsgHandler(old);
5727 QVERIFY(object != 0);
5729 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5730 component.url().toString() +
5731 QLatin1String(":5 depends on non-NOTIFYable properties:");
5732 QString expected2 = QLatin1String(" ") +
5733 QLatin1String(object->metaObject()->className()) +
5734 QLatin1String("::value");
5736 QCOMPARE(messages.length(), 2);
5737 QCOMPARE(messages.at(0), expected1);
5738 QCOMPARE(messages.at(1), expected2);
5743 void tst_qdeclarativeecmascript::forInLoop()
5745 QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
5746 QObject *object = component.create();
5747 QVERIFY(object != 0);
5749 QMetaObject::invokeMethod(object, "listProperty");
5751 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5752 QCOMPARE(r.size(), 3);
5753 QCOMPARE(r[0],QLatin1String("0=obj1"));
5754 QCOMPARE(r[1],QLatin1String("1=obj2"));
5755 QCOMPARE(r[2],QLatin1String("2=obj3"));
5757 //TODO: should test for in loop for other objects (such as QObjects) as well.
5762 // An object the binding depends on is deleted while the binding is still running
5763 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5765 QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
5766 QObject *object = component.create();
5767 QVERIFY(object != 0);
5771 void tst_qdeclarativeecmascript::qtbug_22679()
5774 object.setStringProperty(QLatin1String("Please work correctly"));
5775 engine.rootContext()->setContextProperty("contextProp", &object);
5777 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
5778 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5779 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5781 QObject *o = component.create();
5783 QCOMPARE(warningsSpy.count(), 0);
5787 void tst_qdeclarativeecmascript::qtbug_22843_data()
5789 QTest::addColumn<bool>("library");
5791 QTest::newRow("without .pragma library") << false;
5792 QTest::newRow("with .pragma library") << true;
5795 void tst_qdeclarativeecmascript::qtbug_22843()
5797 QFETCH(bool, library);
5799 QString fileName("qtbug_22843");
5801 fileName += QLatin1String(".library");
5802 fileName += QLatin1String(".qml");
5804 QDeclarativeComponent component(&engine, testFileUrl(fileName));
5805 QString url = component.url().toString();
5806 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5807 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5809 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5810 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5811 for (int x = 0; x < 3; ++x) {
5812 warningsSpy.clear();
5813 // For libraries, only the first import attempt should produce a
5814 // SyntaxError warning; subsequent component creation should not
5815 // attempt to reload the script.
5816 bool expectSyntaxError = !library || (x == 0);
5817 if (expectSyntaxError)
5818 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5819 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5820 QObject *object = component.create();
5821 QVERIFY(object != 0);
5822 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5828 void tst_qdeclarativeecmascript::switchStatement()
5831 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
5832 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5833 QVERIFY(object != 0);
5835 // `object->value()' is the number of executed statements
5837 object->setStringProperty("A");
5838 QCOMPARE(object->value(), 5);
5840 object->setStringProperty("S");
5841 QCOMPARE(object->value(), 3);
5843 object->setStringProperty("D");
5844 QCOMPARE(object->value(), 3);
5846 object->setStringProperty("F");
5847 QCOMPARE(object->value(), 4);
5849 object->setStringProperty("something else");
5850 QCOMPARE(object->value(), 1);
5854 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
5855 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5856 QVERIFY(object != 0);
5858 // `object->value()' is the number of executed statements
5860 object->setStringProperty("A");
5861 QCOMPARE(object->value(), 5);
5863 object->setStringProperty("S");
5864 QCOMPARE(object->value(), 3);
5866 object->setStringProperty("D");
5867 QCOMPARE(object->value(), 3);
5869 object->setStringProperty("F");
5870 QCOMPARE(object->value(), 3);
5872 object->setStringProperty("something else");
5873 QCOMPARE(object->value(), 4);
5877 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
5878 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5879 QVERIFY(object != 0);
5881 // `object->value()' is the number of executed statements
5883 object->setStringProperty("A");
5884 QCOMPARE(object->value(), 5);
5886 object->setStringProperty("S");
5887 QCOMPARE(object->value(), 3);
5889 object->setStringProperty("D");
5890 QCOMPARE(object->value(), 3);
5892 object->setStringProperty("F");
5893 QCOMPARE(object->value(), 3);
5895 object->setStringProperty("something else");
5896 QCOMPARE(object->value(), 6);
5900 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
5902 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5903 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5905 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5906 QVERIFY(object != 0);
5908 // `object->value()' is the number of executed statements
5910 object->setStringProperty("A");
5911 QCOMPARE(object->value(), 5);
5913 object->setStringProperty("S");
5914 QCOMPARE(object->value(), 3);
5916 object->setStringProperty("D");
5917 QCOMPARE(object->value(), 3);
5919 object->setStringProperty("F");
5920 QCOMPARE(object->value(), 3);
5922 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5924 object->setStringProperty("something else");
5928 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
5929 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5930 QVERIFY(object != 0);
5932 // `object->value()' is the number of executed statements
5934 object->setStringProperty("A");
5935 QCOMPARE(object->value(), 1);
5937 object->setStringProperty("S");
5938 QCOMPARE(object->value(), 1);
5940 object->setStringProperty("D");
5941 QCOMPARE(object->value(), 1);
5943 object->setStringProperty("F");
5944 QCOMPARE(object->value(), 1);
5946 object->setStringProperty("something else");
5947 QCOMPARE(object->value(), 1);
5951 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
5952 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5953 QVERIFY(object != 0);
5955 // `object->value()' is the number of executed statements
5957 object->setStringProperty("A");
5958 QCOMPARE(object->value(), 123);
5960 object->setStringProperty("S");
5961 QCOMPARE(object->value(), 123);
5963 object->setStringProperty("D");
5964 QCOMPARE(object->value(), 321);
5966 object->setStringProperty("F");
5967 QCOMPARE(object->value(), 321);
5969 object->setStringProperty("something else");
5970 QCOMPARE(object->value(), 0);
5974 void tst_qdeclarativeecmascript::withStatement()
5977 QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
5978 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5979 QVERIFY(object != 0);
5981 QCOMPARE(object->value(), 123);
5985 void tst_qdeclarativeecmascript::tryStatement()
5988 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
5989 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5990 QVERIFY(object != 0);
5992 QCOMPARE(object->value(), 123);
5996 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
5997 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5998 QVERIFY(object != 0);
6000 QCOMPARE(object->value(), 321);
6004 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
6005 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
6006 QVERIFY(object != 0);
6008 QCOMPARE(object->value(), 1);
6012 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
6013 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
6014 QVERIFY(object != 0);
6016 QCOMPARE(object->value(), 1);
6020 QTEST_MAIN(tst_qdeclarativeecmascript)
6022 #include "tst_qdeclarativeecmascript.moc"