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();
238 void invokableWithQObjectDerived();
240 void automaticSemicolon();
241 void unaryExpression();
242 void switchStatement();
243 void withStatement();
247 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
248 QDeclarativeEngine engine;
251 void tst_qdeclarativeecmascript::initTestCase()
253 QDeclarativeDataTest::initTestCase();
257 void tst_qdeclarativeecmascript::assignBasicTypes()
260 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
261 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
262 QVERIFY(object != 0);
263 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
264 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
265 QCOMPARE(object->stringProperty(), QString("Hello World!"));
266 QCOMPARE(object->uintProperty(), uint(10));
267 QCOMPARE(object->intProperty(), -19);
268 QCOMPARE((float)object->realProperty(), float(23.2));
269 QCOMPARE((float)object->doubleProperty(), float(-19.75));
270 QCOMPARE((float)object->floatProperty(), float(8.5));
271 QCOMPARE(object->colorProperty(), QColor("red"));
272 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
273 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
274 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
275 QCOMPARE(object->pointProperty(), QPoint(99,13));
276 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
277 QCOMPARE(object->sizeProperty(), QSize(99, 13));
278 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
279 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
280 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
281 QCOMPARE(object->boolProperty(), true);
282 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
283 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
284 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
288 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
289 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
290 QVERIFY(object != 0);
291 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
292 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
293 QCOMPARE(object->stringProperty(), QString("Hello World!"));
294 QCOMPARE(object->uintProperty(), uint(10));
295 QCOMPARE(object->intProperty(), -19);
296 QCOMPARE((float)object->realProperty(), float(23.2));
297 QCOMPARE((float)object->doubleProperty(), float(-19.75));
298 QCOMPARE((float)object->floatProperty(), float(8.5));
299 QCOMPARE(object->colorProperty(), QColor("red"));
300 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
301 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
302 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
303 QCOMPARE(object->pointProperty(), QPoint(99,13));
304 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
305 QCOMPARE(object->sizeProperty(), QSize(99, 13));
306 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
307 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
308 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
309 QCOMPARE(object->boolProperty(), true);
310 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
311 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
312 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
317 void tst_qdeclarativeecmascript::idShortcutInvalidates()
320 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
321 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
322 QVERIFY(object != 0);
323 QVERIFY(object->objectProperty() != 0);
324 delete object->objectProperty();
325 QVERIFY(object->objectProperty() == 0);
330 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
331 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
332 QVERIFY(object != 0);
333 QVERIFY(object->objectProperty() != 0);
334 delete object->objectProperty();
335 QVERIFY(object->objectProperty() == 0);
340 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
343 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
344 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
345 QVERIFY(object != 0);
346 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
350 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
351 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
352 QVERIFY(object != 0);
353 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
358 void tst_qdeclarativeecmascript::signalAssignment()
361 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
362 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
363 QVERIFY(object != 0);
364 QCOMPARE(object->string(), QString());
365 emit object->basicSignal();
366 QCOMPARE(object->string(), QString("pass"));
371 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
372 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
373 QVERIFY(object != 0);
374 QCOMPARE(object->string(), QString());
375 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
376 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
381 void tst_qdeclarativeecmascript::methods()
384 QDeclarativeComponent component(&engine, testFileUrl("methods.1.qml"));
385 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
386 QVERIFY(object != 0);
387 QCOMPARE(object->methodCalled(), false);
388 QCOMPARE(object->methodIntCalled(), false);
389 emit object->basicSignal();
390 QCOMPARE(object->methodCalled(), true);
391 QCOMPARE(object->methodIntCalled(), false);
396 QDeclarativeComponent component(&engine, testFileUrl("methods.2.qml"));
397 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
398 QVERIFY(object != 0);
399 QCOMPARE(object->methodCalled(), false);
400 QCOMPARE(object->methodIntCalled(), false);
401 emit object->basicSignal();
402 QCOMPARE(object->methodCalled(), false);
403 QCOMPARE(object->methodIntCalled(), true);
408 QDeclarativeComponent component(&engine, testFileUrl("methods.3.qml"));
409 QObject *object = component.create();
410 QVERIFY(object != 0);
411 QCOMPARE(object->property("test").toInt(), 19);
416 QDeclarativeComponent component(&engine, testFileUrl("methods.4.qml"));
417 QObject *object = component.create();
418 QVERIFY(object != 0);
419 QCOMPARE(object->property("test").toInt(), 19);
420 QCOMPARE(object->property("test2").toInt(), 17);
421 QCOMPARE(object->property("test3").toInt(), 16);
426 QDeclarativeComponent component(&engine, testFileUrl("methods.5.qml"));
427 QObject *object = component.create();
428 QVERIFY(object != 0);
429 QCOMPARE(object->property("test").toInt(), 9);
434 void tst_qdeclarativeecmascript::bindingLoop()
436 QDeclarativeComponent component(&engine, testFileUrl("bindingLoop.qml"));
437 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
438 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
439 QObject *object = component.create();
440 QVERIFY(object != 0);
444 void tst_qdeclarativeecmascript::basicExpressions_data()
446 QTest::addColumn<QString>("expression");
447 QTest::addColumn<QVariant>("result");
448 QTest::addColumn<bool>("nest");
450 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
451 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
452 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
453 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
454 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
455 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
456 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
457 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
458 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
459 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
460 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
461 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
462 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
463 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
464 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
465 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
466 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
467 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
468 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
471 void tst_qdeclarativeecmascript::basicExpressions()
473 QFETCH(QString, expression);
474 QFETCH(QVariant, result);
480 MyDefaultObject1 default1;
481 MyDefaultObject3 default3;
482 object1.setStringProperty("Object1");
483 object2.setStringProperty("Object2");
484 object3.setStringProperty("Object3");
486 QDeclarativeContext context(engine.rootContext());
487 QDeclarativeContext nestedContext(&context);
489 context.setContextObject(&default1);
490 context.setContextProperty("a", QVariant(1944));
491 context.setContextProperty("b", QVariant("Milk"));
492 context.setContextProperty("object", &object1);
493 context.setContextProperty("objectOverride", &object2);
494 nestedContext.setContextObject(&default3);
495 nestedContext.setContextProperty("b", QVariant("Cow"));
496 nestedContext.setContextProperty("objectOverride", &object3);
497 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
499 MyExpression expr(nest?&nestedContext:&context, expression);
500 QCOMPARE(expr.evaluate(), result);
503 void tst_qdeclarativeecmascript::arrayExpressions()
509 QDeclarativeContext context(engine.rootContext());
510 context.setContextProperty("a", &obj1);
511 context.setContextProperty("b", &obj2);
512 context.setContextProperty("c", &obj3);
514 MyExpression expr(&context, "[a, b, c, 10]");
515 QVariant result = expr.evaluate();
516 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
517 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
518 QCOMPARE(list.count(), 4);
519 QCOMPARE(list.at(0), &obj1);
520 QCOMPARE(list.at(1), &obj2);
521 QCOMPARE(list.at(2), &obj3);
522 QCOMPARE(list.at(3), (QObject *)0);
525 // Tests that modifying a context property will reevaluate expressions
526 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
528 QDeclarativeContext context(engine.rootContext());
531 MyQmlObject *object3 = new MyQmlObject;
533 object1.setStringProperty("Hello");
534 object2.setStringProperty("World");
536 context.setContextProperty("testProp", QVariant(1));
537 context.setContextProperty("testObj", &object1);
538 context.setContextProperty("testObj2", object3);
541 MyExpression expr(&context, "testProp + 1");
542 QCOMPARE(expr.changed, false);
543 QCOMPARE(expr.evaluate(), QVariant(2));
545 context.setContextProperty("testProp", QVariant(2));
546 QCOMPARE(expr.changed, true);
547 QCOMPARE(expr.evaluate(), QVariant(3));
551 MyExpression expr(&context, "testProp + testProp + testProp");
552 QCOMPARE(expr.changed, false);
553 QCOMPARE(expr.evaluate(), QVariant(6));
555 context.setContextProperty("testProp", QVariant(4));
556 QCOMPARE(expr.changed, true);
557 QCOMPARE(expr.evaluate(), QVariant(12));
561 MyExpression expr(&context, "testObj.stringProperty");
562 QCOMPARE(expr.changed, false);
563 QCOMPARE(expr.evaluate(), QVariant("Hello"));
565 context.setContextProperty("testObj", &object2);
566 QCOMPARE(expr.changed, true);
567 QCOMPARE(expr.evaluate(), QVariant("World"));
571 MyExpression expr(&context, "testObj.stringProperty /**/");
572 QCOMPARE(expr.changed, false);
573 QCOMPARE(expr.evaluate(), QVariant("World"));
575 context.setContextProperty("testObj", &object1);
576 QCOMPARE(expr.changed, true);
577 QCOMPARE(expr.evaluate(), QVariant("Hello"));
581 MyExpression expr(&context, "testObj2");
582 QCOMPARE(expr.changed, false);
583 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
589 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
591 QDeclarativeContext context(engine.rootContext());
595 context.setContextProperty("testObj", &object1);
597 object1.setStringProperty(QLatin1String("Hello"));
598 object2.setStringProperty(QLatin1String("Dog"));
599 object3.setStringProperty(QLatin1String("Cat"));
602 MyExpression expr(&context, "testObj.stringProperty");
603 QCOMPARE(expr.changed, false);
604 QCOMPARE(expr.evaluate(), QVariant("Hello"));
606 object1.setStringProperty(QLatin1String("World"));
607 QCOMPARE(expr.changed, true);
608 QCOMPARE(expr.evaluate(), QVariant("World"));
612 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
613 QCOMPARE(expr.changed, false);
614 QCOMPARE(expr.evaluate(), QVariant());
616 object1.setObjectProperty(&object2);
617 QCOMPARE(expr.changed, true);
618 expr.changed = false;
619 QCOMPARE(expr.evaluate(), QVariant("Dog"));
621 object1.setObjectProperty(&object3);
622 QCOMPARE(expr.changed, true);
623 expr.changed = false;
624 QCOMPARE(expr.evaluate(), QVariant("Cat"));
626 object1.setObjectProperty(0);
627 QCOMPARE(expr.changed, true);
628 expr.changed = false;
629 QCOMPARE(expr.evaluate(), QVariant());
631 object1.setObjectProperty(&object3);
632 QCOMPARE(expr.changed, true);
633 expr.changed = false;
634 QCOMPARE(expr.evaluate(), QVariant("Cat"));
636 object3.setStringProperty("Donkey");
637 QCOMPARE(expr.changed, true);
638 expr.changed = false;
639 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
643 void tst_qdeclarativeecmascript::deferredProperties()
645 QDeclarativeComponent component(&engine, testFileUrl("deferredProperties.qml"));
646 MyDeferredObject *object =
647 qobject_cast<MyDeferredObject *>(component.create());
648 QVERIFY(object != 0);
649 QCOMPARE(object->value(), 0);
650 QVERIFY(object->objectProperty() == 0);
651 QVERIFY(object->objectProperty2() != 0);
652 qmlExecuteDeferred(object);
653 QCOMPARE(object->value(), 10);
654 QVERIFY(object->objectProperty() != 0);
655 MyQmlObject *qmlObject =
656 qobject_cast<MyQmlObject *>(object->objectProperty());
657 QVERIFY(qmlObject != 0);
658 QCOMPARE(qmlObject->value(), 10);
659 object->setValue(19);
660 QCOMPARE(qmlObject->value(), 19);
665 // Check errors on deferred properties are correctly emitted
666 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
668 QDeclarativeComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
669 MyDeferredObject *object =
670 qobject_cast<MyDeferredObject *>(component.create());
671 QVERIFY(object != 0);
672 QCOMPARE(object->value(), 0);
673 QVERIFY(object->objectProperty() == 0);
674 QVERIFY(object->objectProperty2() == 0);
676 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
677 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
679 qmlExecuteDeferred(object);
684 void tst_qdeclarativeecmascript::extensionObjects()
686 QDeclarativeComponent component(&engine, testFileUrl("extensionObjects.qml"));
687 MyExtendedObject *object =
688 qobject_cast<MyExtendedObject *>(component.create());
689 QVERIFY(object != 0);
690 QCOMPARE(object->baseProperty(), 13);
691 QCOMPARE(object->coreProperty(), 9);
692 object->setProperty("extendedProperty", QVariant(11));
693 object->setProperty("baseExtendedProperty", QVariant(92));
694 QCOMPARE(object->coreProperty(), 11);
695 QCOMPARE(object->baseProperty(), 92);
697 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
699 QCOMPARE(nested->baseProperty(), 13);
700 QCOMPARE(nested->coreProperty(), 9);
701 nested->setProperty("extendedProperty", QVariant(11));
702 nested->setProperty("baseExtendedProperty", QVariant(92));
703 QCOMPARE(nested->coreProperty(), 11);
704 QCOMPARE(nested->baseProperty(), 92);
709 void tst_qdeclarativeecmascript::overrideExtensionProperties()
711 QDeclarativeComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
712 OverrideDefaultPropertyObject *object =
713 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
714 QVERIFY(object != 0);
715 QVERIFY(object->secondProperty() != 0);
716 QVERIFY(object->firstProperty() == 0);
721 void tst_qdeclarativeecmascript::attachedProperties()
724 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.qml"));
725 QObject *object = component.create();
726 QVERIFY(object != 0);
727 QCOMPARE(object->property("a").toInt(), 19);
728 QCOMPARE(object->property("b").toInt(), 19);
729 QCOMPARE(object->property("c").toInt(), 19);
730 QCOMPARE(object->property("d").toInt(), 19);
735 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
736 QObject *object = component.create();
737 QVERIFY(object != 0);
738 QCOMPARE(object->property("a").toInt(), 26);
739 QCOMPARE(object->property("b").toInt(), 26);
740 QCOMPARE(object->property("c").toInt(), 26);
741 QCOMPARE(object->property("d").toInt(), 26);
747 QDeclarativeComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
748 QObject *object = component.create();
749 QVERIFY(object != 0);
751 QMetaObject::invokeMethod(object, "writeValue2");
753 MyQmlAttachedObject *attached =
754 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
755 QVERIFY(attached != 0);
757 QCOMPARE(attached->value2(), 9);
762 void tst_qdeclarativeecmascript::enums()
766 QDeclarativeComponent component(&engine, testFileUrl("enums.1.qml"));
767 QObject *object = component.create();
768 QVERIFY(object != 0);
770 QCOMPARE(object->property("a").toInt(), 0);
771 QCOMPARE(object->property("b").toInt(), 1);
772 QCOMPARE(object->property("c").toInt(), 2);
773 QCOMPARE(object->property("d").toInt(), 3);
774 QCOMPARE(object->property("e").toInt(), 0);
775 QCOMPARE(object->property("f").toInt(), 1);
776 QCOMPARE(object->property("g").toInt(), 2);
777 QCOMPARE(object->property("h").toInt(), 3);
778 QCOMPARE(object->property("i").toInt(), 19);
779 QCOMPARE(object->property("j").toInt(), 19);
783 // Non-existent enums
785 QDeclarativeComponent component(&engine, testFileUrl("enums.2.qml"));
787 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
788 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
789 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
790 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
792 QObject *object = component.create();
793 QVERIFY(object != 0);
794 QCOMPARE(object->property("a").toInt(), 0);
795 QCOMPARE(object->property("b").toInt(), 0);
801 void tst_qdeclarativeecmascript::valueTypeFunctions()
803 QDeclarativeComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
804 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
806 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
807 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
813 Tests that writing a constant to a property with a binding on it disables the
816 void tst_qdeclarativeecmascript::constantsOverrideBindings()
820 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
821 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
822 QVERIFY(object != 0);
824 QCOMPARE(object->property("c2").toInt(), 0);
825 object->setProperty("c1", QVariant(9));
826 QCOMPARE(object->property("c2").toInt(), 9);
828 emit object->basicSignal();
830 QCOMPARE(object->property("c2").toInt(), 13);
831 object->setProperty("c1", QVariant(8));
832 QCOMPARE(object->property("c2").toInt(), 13);
837 // During construction
839 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
840 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
841 QVERIFY(object != 0);
843 QCOMPARE(object->property("c1").toInt(), 0);
844 QCOMPARE(object->property("c2").toInt(), 10);
845 object->setProperty("c1", QVariant(9));
846 QCOMPARE(object->property("c1").toInt(), 9);
847 QCOMPARE(object->property("c2").toInt(), 10);
855 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.3.qml"));
856 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
857 QVERIFY(object != 0);
859 QCOMPARE(object->property("c2").toInt(), 0);
860 object->setProperty("c1", QVariant(9));
861 QCOMPARE(object->property("c2").toInt(), 9);
863 object->setProperty("c2", QVariant(13));
864 QCOMPARE(object->property("c2").toInt(), 13);
865 object->setProperty("c1", QVariant(7));
866 QCOMPARE(object->property("c1").toInt(), 7);
867 QCOMPARE(object->property("c2").toInt(), 13);
875 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
876 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
877 QVERIFY(object != 0);
879 QCOMPARE(object->property("c1").toInt(), 0);
880 QCOMPARE(object->property("c3").toInt(), 10);
881 object->setProperty("c1", QVariant(9));
882 QCOMPARE(object->property("c1").toInt(), 9);
883 QCOMPARE(object->property("c3").toInt(), 10);
890 Tests that assigning a binding to a property that already has a binding causes
891 the original binding to be disabled.
893 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
895 QDeclarativeComponent component(&engine,
896 testFileUrl("outerBindingOverridesInnerBinding.qml"));
897 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
898 QVERIFY(object != 0);
900 QCOMPARE(object->property("c1").toInt(), 0);
901 QCOMPARE(object->property("c2").toInt(), 0);
902 QCOMPARE(object->property("c3").toInt(), 0);
904 object->setProperty("c1", QVariant(9));
905 QCOMPARE(object->property("c1").toInt(), 9);
906 QCOMPARE(object->property("c2").toInt(), 0);
907 QCOMPARE(object->property("c3").toInt(), 0);
909 object->setProperty("c3", QVariant(8));
910 QCOMPARE(object->property("c1").toInt(), 9);
911 QCOMPARE(object->property("c2").toInt(), 8);
912 QCOMPARE(object->property("c3").toInt(), 8);
918 Access a non-existent attached object.
920 Tests for a regression where this used to crash.
922 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
924 QDeclarativeComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
926 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
927 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
929 QObject *object = component.create();
930 QVERIFY(object != 0);
935 void tst_qdeclarativeecmascript::scope()
938 QDeclarativeComponent component(&engine, testFileUrl("scope.qml"));
939 QObject *object = component.create();
940 QVERIFY(object != 0);
942 QCOMPARE(object->property("test1").toInt(), 1);
943 QCOMPARE(object->property("test2").toInt(), 2);
944 QCOMPARE(object->property("test3").toString(), QString("1Test"));
945 QCOMPARE(object->property("test4").toString(), QString("2Test"));
946 QCOMPARE(object->property("test5").toInt(), 1);
947 QCOMPARE(object->property("test6").toInt(), 1);
948 QCOMPARE(object->property("test7").toInt(), 2);
949 QCOMPARE(object->property("test8").toInt(), 2);
950 QCOMPARE(object->property("test9").toInt(), 1);
951 QCOMPARE(object->property("test10").toInt(), 3);
957 QDeclarativeComponent component(&engine, testFileUrl("scope.2.qml"));
958 QObject *object = component.create();
959 QVERIFY(object != 0);
961 QCOMPARE(object->property("test1").toInt(), 19);
962 QCOMPARE(object->property("test2").toInt(), 19);
963 QCOMPARE(object->property("test3").toInt(), 14);
964 QCOMPARE(object->property("test4").toInt(), 14);
965 QCOMPARE(object->property("test5").toInt(), 24);
966 QCOMPARE(object->property("test6").toInt(), 24);
972 QDeclarativeComponent component(&engine, testFileUrl("scope.3.qml"));
973 QObject *object = component.create();
974 QVERIFY(object != 0);
976 QCOMPARE(object->property("test1").toBool(), true);
977 QCOMPARE(object->property("test2").toBool(), true);
978 QCOMPARE(object->property("test3").toBool(), true);
983 // Signal argument scope
985 QDeclarativeComponent component(&engine, testFileUrl("scope.4.qml"));
986 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
987 QVERIFY(object != 0);
989 QCOMPARE(object->property("test").toInt(), 0);
990 QCOMPARE(object->property("test2").toString(), QString());
992 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
994 QCOMPARE(object->property("test").toInt(), 13);
995 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
1001 QDeclarativeComponent component(&engine, testFileUrl("scope.5.qml"));
1002 QObject *object = component.create();
1003 QVERIFY(object != 0);
1005 QCOMPARE(object->property("test1").toBool(), true);
1006 QCOMPARE(object->property("test2").toBool(), true);
1012 QDeclarativeComponent component(&engine, testFileUrl("scope.6.qml"));
1013 QObject *object = component.create();
1014 QVERIFY(object != 0);
1016 QCOMPARE(object->property("test").toBool(), true);
1022 // In 4.7, non-library javascript files that had no imports shared the imports of their
1023 // importing context
1024 void tst_qdeclarativeecmascript::importScope()
1026 QDeclarativeComponent component(&engine, testFileUrl("importScope.qml"));
1027 QObject *o = component.create();
1030 QCOMPARE(o->property("test").toInt(), 240);
1036 Tests that "any" type passes through a synthesized signal parameter. This
1037 is essentially a test of QDeclarativeMetaType::copy()
1039 void tst_qdeclarativeecmascript::signalParameterTypes()
1041 QDeclarativeComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
1042 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1043 QVERIFY(object != 0);
1045 emit object->basicSignal();
1047 QCOMPARE(object->property("intProperty").toInt(), 10);
1048 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1049 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1050 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1051 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1052 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1058 Test that two JS objects for the same QObject compare as equal.
1060 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1062 QDeclarativeComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
1063 QObject *object = component.create();
1064 QVERIFY(object != 0);
1066 QCOMPARE(object->property("test1").toBool(), true);
1067 QCOMPARE(object->property("test2").toBool(), true);
1068 QCOMPARE(object->property("test3").toBool(), true);
1069 QCOMPARE(object->property("test4").toBool(), true);
1070 QCOMPARE(object->property("test5").toBool(), true);
1076 Confirm bindings and alias properties can coexist.
1078 Tests for a regression where the binding would not reevaluate.
1080 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1082 QDeclarativeComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
1083 QObject *object = component.create();
1084 QVERIFY(object != 0);
1086 QCOMPARE(object->property("c2").toInt(), 3);
1087 QCOMPARE(object->property("c3").toInt(), 3);
1089 object->setProperty("c2", QVariant(19));
1091 QCOMPARE(object->property("c2").toInt(), 19);
1092 QCOMPARE(object->property("c3").toInt(), 19);
1098 Ensure that we can write undefined value to an alias property,
1099 and that the aliased property is reset correctly if possible.
1101 void tst_qdeclarativeecmascript::aliasPropertyReset()
1103 QObject *object = 0;
1105 // test that a manual write (of undefined) to a resettable aliased property succeeds
1106 QDeclarativeComponent c1(&engine, testFileUrl("aliasreset/aliasPropertyReset.1.qml"));
1107 object = c1.create();
1108 QVERIFY(object != 0);
1109 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1110 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1111 QMetaObject::invokeMethod(object, "resetAliased");
1112 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1113 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1116 // test that a manual write (of undefined) to a resettable alias property succeeds
1117 QDeclarativeComponent c2(&engine, testFileUrl("aliasreset/aliasPropertyReset.2.qml"));
1118 object = c2.create();
1119 QVERIFY(object != 0);
1120 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1121 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1122 QMetaObject::invokeMethod(object, "resetAlias");
1123 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1124 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1127 // test that an alias to a bound property works correctly
1128 QDeclarativeComponent c3(&engine, testFileUrl("aliasreset/aliasPropertyReset.3.qml"));
1129 object = c3.create();
1130 QVERIFY(object != 0);
1131 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1132 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1133 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1134 QMetaObject::invokeMethod(object, "resetAlias");
1135 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1136 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1137 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1140 // test that a manual write (of undefined) to a resettable alias property
1141 // whose aliased property's object has been deleted, does not crash.
1142 QDeclarativeComponent c4(&engine, testFileUrl("aliasreset/aliasPropertyReset.4.qml"));
1143 object = c4.create();
1144 QVERIFY(object != 0);
1145 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1146 QObject *loader = object->findChild<QObject*>("loader");
1147 QVERIFY(loader != 0);
1149 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1150 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1151 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1152 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1153 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1156 // test that binding an alias property to an undefined value works correctly
1157 QDeclarativeComponent c5(&engine, testFileUrl("aliasreset/aliasPropertyReset.5.qml"));
1158 object = c5.create();
1159 QVERIFY(object != 0);
1160 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1163 // test that a manual write (of undefined) to a non-resettable property fails properly
1164 QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
1165 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1166 QDeclarativeComponent e1(&engine, url);
1167 object = e1.create();
1168 QVERIFY(object != 0);
1169 QCOMPARE(object->property("intAlias").value<int>(), 12);
1170 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1171 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1172 QMetaObject::invokeMethod(object, "resetAlias");
1173 QCOMPARE(object->property("intAlias").value<int>(), 12);
1174 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1178 void tst_qdeclarativeecmascript::dynamicCreation_data()
1180 QTest::addColumn<QString>("method");
1181 QTest::addColumn<QString>("createdName");
1183 QTest::newRow("One") << "createOne" << "objectOne";
1184 QTest::newRow("Two") << "createTwo" << "objectTwo";
1185 QTest::newRow("Three") << "createThree" << "objectThree";
1189 Test using createQmlObject to dynamically generate an item
1190 Also using createComponent is tested.
1192 void tst_qdeclarativeecmascript::dynamicCreation()
1194 QFETCH(QString, method);
1195 QFETCH(QString, createdName);
1197 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1198 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1199 QVERIFY(object != 0);
1201 QMetaObject::invokeMethod(object, method.toUtf8());
1202 QObject *created = object->objectProperty();
1204 QCOMPARE(created->objectName(), createdName);
1210 Tests the destroy function
1212 void tst_qdeclarativeecmascript::dynamicDestruction()
1215 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
1216 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1217 QVERIFY(object != 0);
1218 QDeclarativeGuard<QObject> createdQmlObject = 0;
1220 QMetaObject::invokeMethod(object, "create");
1221 createdQmlObject = object->objectProperty();
1222 QVERIFY(createdQmlObject);
1223 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1225 QMetaObject::invokeMethod(object, "killOther");
1226 QVERIFY(createdQmlObject);
1228 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1229 QCoreApplication::processEvents();
1230 QVERIFY(createdQmlObject);
1231 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1232 if (createdQmlObject) {
1234 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1235 QCoreApplication::processEvents();
1238 QVERIFY(!createdQmlObject);
1240 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1241 QMetaObject::invokeMethod(object, "killMe");
1243 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1244 QCoreApplication::processEvents();
1249 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
1250 QObject *o = component.create();
1253 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1255 QMetaObject::invokeMethod(o, "create");
1257 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1259 QMetaObject::invokeMethod(o, "destroy");
1261 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1262 QCoreApplication::processEvents();
1264 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1271 tests that id.toString() works
1273 void tst_qdeclarativeecmascript::objectToString()
1275 QDeclarativeComponent component(&engine, testFileUrl("declarativeToString.qml"));
1276 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1277 QVERIFY(object != 0);
1278 QMetaObject::invokeMethod(object, "testToString");
1279 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1280 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1286 tests that id.hasOwnProperty() works
1288 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1290 QUrl url = testFileUrl("declarativeHasOwnProperty.qml");
1291 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1292 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1293 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1295 QDeclarativeComponent component(&engine, url);
1296 QObject *object = component.create();
1297 QVERIFY(object != 0);
1299 // test QObjects in QML
1300 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1301 QVERIFY(object->property("result").value<bool>() == true);
1302 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1303 QVERIFY(object->property("result").value<bool>() == false);
1305 // now test other types in QML
1306 QObject *child = object->findChild<QObject*>("typeObj");
1307 QVERIFY(child != 0);
1308 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1309 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1310 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1311 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1312 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1313 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1314 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1315 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1316 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1317 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1318 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1319 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1321 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1322 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1323 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1324 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1325 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1326 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1327 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1328 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1329 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1335 Tests bindings that indirectly cause their own deletion work.
1337 This test is best run under valgrind to ensure no invalid memory access occur.
1339 void tst_qdeclarativeecmascript::selfDeletingBinding()
1342 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
1343 QObject *object = component.create();
1344 QVERIFY(object != 0);
1345 object->setProperty("triggerDelete", true);
1350 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
1351 QObject *object = component.create();
1352 QVERIFY(object != 0);
1353 object->setProperty("triggerDelete", true);
1359 Test that extended object properties can be accessed.
1361 This test a regression where this used to crash. The issue was specificially
1362 for extended objects that did not include a synthesized meta object (so non-root
1363 and no synthesiszed properties).
1365 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1367 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
1368 QObject *object = component.create();
1369 QVERIFY(object != 0);
1374 Test that extended object properties can be accessed correctly.
1376 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
1378 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
1379 QObject *object = component.create();
1380 QVERIFY(object != 0);
1382 QVariant returnValue;
1383 QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
1384 QCOMPARE(returnValue.toInt(), 42);
1389 Test file/lineNumbers for binding/Script errors.
1391 void tst_qdeclarativeecmascript::scriptErrors()
1393 QDeclarativeComponent component(&engine, testFileUrl("scriptErrors.qml"));
1394 QString url = component.url().toString();
1396 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1397 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1398 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1399 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1400 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1401 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1402 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1403 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1405 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1406 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1407 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1408 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1409 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1410 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1411 QVERIFY(object != 0);
1413 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1414 emit object->basicSignal();
1416 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1417 emit object->anotherBasicSignal();
1419 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1420 emit object->thirdBasicSignal();
1426 Test file/lineNumbers for inline functions.
1428 void tst_qdeclarativeecmascript::functionErrors()
1430 QDeclarativeComponent component(&engine, testFileUrl("functionErrors.qml"));
1431 QString url = component.url().toString();
1433 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1435 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1437 QObject *object = component.create();
1438 QVERIFY(object != 0);
1441 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1442 QDeclarativeComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
1443 url = componentTwo.url().toString();
1444 object = componentTwo.create();
1445 QVERIFY(object != 0);
1447 QString srpname = object->property("srp_name").toString();
1449 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1450 + QLatin1String(" is not a function");
1451 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1452 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1457 Test various errors that can occur when assigning a property from script
1459 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1461 QDeclarativeComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
1463 QString url = component.url().toString();
1465 QObject *object = component.create();
1466 QVERIFY(object != 0);
1468 QCOMPARE(object->property("test1").toBool(), true);
1469 QCOMPARE(object->property("test2").toBool(), true);
1475 Test bindings still work when the reeval is triggered from within
1478 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1480 QDeclarativeComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
1481 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1482 QVERIFY(object != 0);
1484 QCOMPARE(object->property("base").toReal(), 50.);
1485 QCOMPARE(object->property("test1").toReal(), 50.);
1486 QCOMPARE(object->property("test2").toReal(), 50.);
1488 object->basicSignal();
1490 QCOMPARE(object->property("base").toReal(), 200.);
1491 QCOMPARE(object->property("test1").toReal(), 200.);
1492 QCOMPARE(object->property("test2").toReal(), 200.);
1494 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1496 QCOMPARE(object->property("base").toReal(), 400.);
1497 QCOMPARE(object->property("test1").toReal(), 400.);
1498 QCOMPARE(object->property("test2").toReal(), 400.);
1504 Test that list properties can be iterated from ECMAScript
1506 void tst_qdeclarativeecmascript::listProperties()
1508 QDeclarativeComponent component(&engine, testFileUrl("listProperties.qml"));
1509 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1510 QVERIFY(object != 0);
1512 QCOMPARE(object->property("test1").toInt(), 21);
1513 QCOMPARE(object->property("test2").toInt(), 2);
1514 QCOMPARE(object->property("test3").toBool(), true);
1515 QCOMPARE(object->property("test4").toBool(), true);
1520 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1522 QDeclarativeComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
1523 QString url = component.url().toString();
1525 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1527 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1528 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1529 QVERIFY(object != 0);
1531 QCOMPARE(object->property("test").toBool(), false);
1533 MyQmlObject object2;
1534 MyQmlObject object3;
1535 object2.setObjectProperty(&object3);
1536 object->setObjectProperty(&object2);
1538 QCOMPARE(object->property("test").toBool(), true);
1543 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1545 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
1546 QString url = component.url().toString();
1548 QString warning = component.url().toString() + ":6: Error: JS exception";
1550 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1551 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1552 QVERIFY(object != 0);
1556 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1558 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
1559 QString url = component.url().toString();
1561 QString warning = component.url().toString() + ":5: Error: JS exception";
1563 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1564 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1565 QVERIFY(object != 0);
1569 void tst_qdeclarativeecmascript::compileInvalidBinding()
1571 // QTBUG-23387: ensure that invalid bindings don't cause a crash.
1572 QDeclarativeComponent component(&engine, testFileUrl("v8bindingException.qml"));
1573 QString warning = component.url().toString() + ":16: SyntaxError: Unexpected token ILLEGAL";
1574 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1575 QObject *object = component.create();
1576 QVERIFY(object != 0);
1580 static int transientErrorsMsgCount = 0;
1581 static void transientErrorsMsgHandler(QtMsgType, const char *)
1583 ++transientErrorsMsgCount;
1586 // Check that transient binding errors are not displayed
1587 void tst_qdeclarativeecmascript::transientErrors()
1590 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
1592 transientErrorsMsgCount = 0;
1593 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1595 QObject *object = component.create();
1596 QVERIFY(object != 0);
1598 qInstallMsgHandler(old);
1600 QCOMPARE(transientErrorsMsgCount, 0);
1605 // One binding erroring multiple times, but then resolving
1607 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
1609 transientErrorsMsgCount = 0;
1610 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1612 QObject *object = component.create();
1613 QVERIFY(object != 0);
1615 qInstallMsgHandler(old);
1617 QCOMPARE(transientErrorsMsgCount, 0);
1623 // Check that errors during shutdown are minimized
1624 void tst_qdeclarativeecmascript::shutdownErrors()
1626 QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
1627 QObject *object = component.create();
1628 QVERIFY(object != 0);
1630 transientErrorsMsgCount = 0;
1631 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1635 qInstallMsgHandler(old);
1636 QCOMPARE(transientErrorsMsgCount, 0);
1639 void tst_qdeclarativeecmascript::compositePropertyType()
1641 QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
1643 QTest::ignoreMessage(QtDebugMsg, "hello world");
1644 QObject *object = qobject_cast<QObject *>(component.create());
1649 void tst_qdeclarativeecmascript::jsObject()
1651 QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
1652 QObject *object = component.create();
1653 QVERIFY(object != 0);
1655 QCOMPARE(object->property("test").toInt(), 92);
1660 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1663 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
1664 QObject *object = component.create();
1665 QVERIFY(object != 0);
1667 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1669 object->setProperty("setUndefined", true);
1671 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1673 object->setProperty("setUndefined", false);
1675 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1680 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
1681 QObject *object = component.create();
1682 QVERIFY(object != 0);
1684 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1686 QMetaObject::invokeMethod(object, "doReset");
1688 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1694 // Aliases to variant properties should work
1695 void tst_qdeclarativeecmascript::qtbug_22464()
1697 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
1698 QObject *object = component.create();
1699 QVERIFY(object != 0);
1701 QCOMPARE(object->property("test").toBool(), true);
1706 void tst_qdeclarativeecmascript::qtbug_21580()
1708 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
1710 QObject *object = component.create();
1711 QVERIFY(object != 0);
1713 QCOMPARE(object->property("test").toBool(), true);
1719 void tst_qdeclarativeecmascript::bug1()
1721 QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
1722 QObject *object = component.create();
1723 QVERIFY(object != 0);
1725 QCOMPARE(object->property("test").toInt(), 14);
1727 object->setProperty("a", 11);
1729 QCOMPARE(object->property("test").toInt(), 3);
1731 object->setProperty("b", true);
1733 QCOMPARE(object->property("test").toInt(), 9);
1738 void tst_qdeclarativeecmascript::bug2()
1740 QDeclarativeComponent component(&engine);
1741 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1743 QObject *object = component.create();
1744 QVERIFY(object != 0);
1749 // Don't crash in createObject when the component has errors.
1750 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1752 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1753 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1754 QVERIFY(object != 0);
1756 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1757 QMetaObject::invokeMethod(object, "dontCrash");
1758 QObject *created = object->objectProperty();
1759 QVERIFY(created == 0);
1764 // ownership transferred to JS, ensure that GC runs the dtor
1765 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1768 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1770 // allow the engine to go out of scope too.
1772 QDeclarativeEngine dcoEngine;
1773 QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
1774 QObject *object = component.create();
1775 QVERIFY(object != 0);
1776 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1777 QVERIFY(mdcdo != 0);
1778 mdcdo->setDtorCount(&dtorCount);
1780 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1781 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1783 // we do this once manually, but it should be done automatically
1784 // when the engine goes out of scope (since it should gc in dtor)
1785 QMetaObject::invokeMethod(object, "performGc");
1788 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1789 QCoreApplication::processEvents();
1795 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1796 QCoreApplication::processEvents();
1797 QCOMPARE(dtorCount, expectedDtorCount);
1800 void tst_qdeclarativeecmascript::regExpBug()
1804 QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
1805 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1806 QVERIFY(object != 0);
1807 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1813 QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
1814 QDeclarativeComponent component(&engine, testFileUrl("regExp.2.qml"));
1815 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1816 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1818 QCOMPARE(component.errorString(), err);
1822 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1824 QString functionSource = QLatin1String("(function(object) { return ") +
1825 QLatin1String(source) + QLatin1String(" })");
1827 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1830 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1831 if (function.IsEmpty())
1833 v8::Handle<v8::Value> args[] = { o };
1834 function->Call(engine->global(), 1, args);
1835 return tc.HasCaught();
1838 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1839 const char *source, v8::Handle<v8::Value> result)
1841 QString functionSource = QLatin1String("(function(object) { return ") +
1842 QLatin1String(source) + QLatin1String(" })");
1844 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1847 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1848 if (function.IsEmpty())
1850 v8::Handle<v8::Value> args[] = { o };
1852 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1857 return value->StrictEquals(result);
1860 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1863 QString functionSource = QLatin1String("(function(object) { return ") +
1864 QLatin1String(source) + QLatin1String(" })");
1866 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1868 return v8::Handle<v8::Value>();
1869 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1870 if (function.IsEmpty())
1871 return v8::Handle<v8::Value>();
1872 v8::Handle<v8::Value> args[] = { o };
1874 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1877 return v8::Handle<v8::Value>();
1881 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1882 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1883 #define EVALUATE(source) evaluate(engine, object, source)
1885 void tst_qdeclarativeecmascript::callQtInvokables()
1887 MyInvokableObject o;
1889 QDeclarativeEngine qmlengine;
1890 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1892 QV8Engine *engine = ep->v8engine();
1894 v8::HandleScope handle_scope;
1895 v8::Context::Scope scope(engine->context());
1897 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1899 // Non-existent methods
1901 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1902 QCOMPARE(o.error(), false);
1903 QCOMPARE(o.invoked(), -1);
1904 QCOMPARE(o.actuals().count(), 0);
1907 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1908 QCOMPARE(o.error(), false);
1909 QCOMPARE(o.invoked(), -1);
1910 QCOMPARE(o.actuals().count(), 0);
1912 // Insufficient arguments
1914 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1915 QCOMPARE(o.error(), false);
1916 QCOMPARE(o.invoked(), -1);
1917 QCOMPARE(o.actuals().count(), 0);
1920 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1921 QCOMPARE(o.error(), false);
1922 QCOMPARE(o.invoked(), -1);
1923 QCOMPARE(o.actuals().count(), 0);
1925 // Excessive arguments
1927 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1928 QCOMPARE(o.error(), false);
1929 QCOMPARE(o.invoked(), 8);
1930 QCOMPARE(o.actuals().count(), 1);
1931 QCOMPARE(o.actuals().at(0), QVariant(10));
1934 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1935 QCOMPARE(o.error(), false);
1936 QCOMPARE(o.invoked(), 9);
1937 QCOMPARE(o.actuals().count(), 2);
1938 QCOMPARE(o.actuals().at(0), QVariant(10));
1939 QCOMPARE(o.actuals().at(1), QVariant(11));
1941 // Test return types
1943 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1944 QCOMPARE(o.error(), false);
1945 QCOMPARE(o.invoked(), 0);
1946 QCOMPARE(o.actuals().count(), 0);
1949 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1950 QCOMPARE(o.error(), false);
1951 QCOMPARE(o.invoked(), 1);
1952 QCOMPARE(o.actuals().count(), 0);
1955 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1956 QCOMPARE(o.error(), false);
1957 QCOMPARE(o.invoked(), 2);
1958 QCOMPARE(o.actuals().count(), 0);
1962 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1963 QVERIFY(!ret.IsEmpty());
1964 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1965 QCOMPARE(o.error(), false);
1966 QCOMPARE(o.invoked(), 3);
1967 QCOMPARE(o.actuals().count(), 0);
1972 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1973 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1974 QCOMPARE(o.error(), false);
1975 QCOMPARE(o.invoked(), 4);
1976 QCOMPARE(o.actuals().count(), 0);
1980 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1981 QCOMPARE(o.error(), false);
1982 QCOMPARE(o.invoked(), 5);
1983 QCOMPARE(o.actuals().count(), 0);
1987 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1988 QVERIFY(ret->IsString());
1989 QCOMPARE(engine->toString(ret), QString("Hello world"));
1990 QCOMPARE(o.error(), false);
1991 QCOMPARE(o.invoked(), 6);
1992 QCOMPARE(o.actuals().count(), 0);
1996 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1997 QCOMPARE(o.error(), false);
1998 QCOMPARE(o.invoked(), 7);
1999 QCOMPARE(o.actuals().count(), 0);
2003 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
2004 QCOMPARE(o.error(), false);
2005 QCOMPARE(o.invoked(), 8);
2006 QCOMPARE(o.actuals().count(), 1);
2007 QCOMPARE(o.actuals().at(0), QVariant(94));
2010 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
2011 QCOMPARE(o.error(), false);
2012 QCOMPARE(o.invoked(), 8);
2013 QCOMPARE(o.actuals().count(), 1);
2014 QCOMPARE(o.actuals().at(0), QVariant(94));
2017 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
2018 QCOMPARE(o.error(), false);
2019 QCOMPARE(o.invoked(), 8);
2020 QCOMPARE(o.actuals().count(), 1);
2021 QCOMPARE(o.actuals().at(0), QVariant(0));
2024 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
2025 QCOMPARE(o.error(), false);
2026 QCOMPARE(o.invoked(), 8);
2027 QCOMPARE(o.actuals().count(), 1);
2028 QCOMPARE(o.actuals().at(0), QVariant(0));
2031 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
2032 QCOMPARE(o.error(), false);
2033 QCOMPARE(o.invoked(), 8);
2034 QCOMPARE(o.actuals().count(), 1);
2035 QCOMPARE(o.actuals().at(0), QVariant(0));
2038 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2039 QCOMPARE(o.error(), false);
2040 QCOMPARE(o.invoked(), 8);
2041 QCOMPARE(o.actuals().count(), 1);
2042 QCOMPARE(o.actuals().at(0), QVariant(0));
2045 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2046 QCOMPARE(o.error(), false);
2047 QCOMPARE(o.invoked(), 9);
2048 QCOMPARE(o.actuals().count(), 2);
2049 QCOMPARE(o.actuals().at(0), QVariant(122));
2050 QCOMPARE(o.actuals().at(1), QVariant(9));
2053 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2054 QCOMPARE(o.error(), false);
2055 QCOMPARE(o.invoked(), 10);
2056 QCOMPARE(o.actuals().count(), 1);
2057 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2060 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2061 QCOMPARE(o.error(), false);
2062 QCOMPARE(o.invoked(), 10);
2063 QCOMPARE(o.actuals().count(), 1);
2064 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2067 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2068 QCOMPARE(o.error(), false);
2069 QCOMPARE(o.invoked(), 10);
2070 QCOMPARE(o.actuals().count(), 1);
2071 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2074 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2075 QCOMPARE(o.error(), false);
2076 QCOMPARE(o.invoked(), 10);
2077 QCOMPARE(o.actuals().count(), 1);
2078 QCOMPARE(o.actuals().at(0), QVariant(0));
2081 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2082 QCOMPARE(o.error(), false);
2083 QCOMPARE(o.invoked(), 10);
2084 QCOMPARE(o.actuals().count(), 1);
2085 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2088 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2089 QCOMPARE(o.error(), false);
2090 QCOMPARE(o.invoked(), 10);
2091 QCOMPARE(o.actuals().count(), 1);
2092 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2095 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2096 QCOMPARE(o.error(), false);
2097 QCOMPARE(o.invoked(), 11);
2098 QCOMPARE(o.actuals().count(), 1);
2099 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2102 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2103 QCOMPARE(o.error(), false);
2104 QCOMPARE(o.invoked(), 11);
2105 QCOMPARE(o.actuals().count(), 1);
2106 QCOMPARE(o.actuals().at(0), QVariant("19"));
2110 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2111 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2112 QCOMPARE(o.error(), false);
2113 QCOMPARE(o.invoked(), 11);
2114 QCOMPARE(o.actuals().count(), 1);
2115 QCOMPARE(o.actuals().at(0), QVariant(expected));
2119 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2120 QCOMPARE(o.error(), false);
2121 QCOMPARE(o.invoked(), 11);
2122 QCOMPARE(o.actuals().count(), 1);
2123 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2126 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2127 QCOMPARE(o.error(), false);
2128 QCOMPARE(o.invoked(), 11);
2129 QCOMPARE(o.actuals().count(), 1);
2130 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2133 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2134 QCOMPARE(o.error(), false);
2135 QCOMPARE(o.invoked(), 12);
2136 QCOMPARE(o.actuals().count(), 1);
2137 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2140 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2141 QCOMPARE(o.error(), false);
2142 QCOMPARE(o.invoked(), 12);
2143 QCOMPARE(o.actuals().count(), 1);
2144 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2147 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2148 QCOMPARE(o.error(), false);
2149 QCOMPARE(o.invoked(), 12);
2150 QCOMPARE(o.actuals().count(), 1);
2151 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2154 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2155 QCOMPARE(o.error(), false);
2156 QCOMPARE(o.invoked(), 12);
2157 QCOMPARE(o.actuals().count(), 1);
2158 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2161 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2162 QCOMPARE(o.error(), false);
2163 QCOMPARE(o.invoked(), 12);
2164 QCOMPARE(o.actuals().count(), 1);
2165 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2168 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2169 QCOMPARE(o.error(), false);
2170 QCOMPARE(o.invoked(), 12);
2171 QCOMPARE(o.actuals().count(), 1);
2172 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2175 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2176 QCOMPARE(o.error(), false);
2177 QCOMPARE(o.invoked(), 13);
2178 QCOMPARE(o.actuals().count(), 1);
2179 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2182 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2183 QCOMPARE(o.error(), false);
2184 QCOMPARE(o.invoked(), 13);
2185 QCOMPARE(o.actuals().count(), 1);
2186 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2189 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2190 QCOMPARE(o.error(), false);
2191 QCOMPARE(o.invoked(), 13);
2192 QCOMPARE(o.actuals().count(), 1);
2193 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2196 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2197 QCOMPARE(o.error(), false);
2198 QCOMPARE(o.invoked(), 13);
2199 QCOMPARE(o.actuals().count(), 1);
2200 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2203 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2204 QCOMPARE(o.error(), false);
2205 QCOMPARE(o.invoked(), 13);
2206 QCOMPARE(o.actuals().count(), 1);
2207 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2210 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2211 QCOMPARE(o.error(), false);
2212 QCOMPARE(o.invoked(), 14);
2213 QCOMPARE(o.actuals().count(), 1);
2214 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2217 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2218 QCOMPARE(o.error(), false);
2219 QCOMPARE(o.invoked(), 14);
2220 QCOMPARE(o.actuals().count(), 1);
2221 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2224 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2225 QCOMPARE(o.error(), false);
2226 QCOMPARE(o.invoked(), 14);
2227 QCOMPARE(o.actuals().count(), 1);
2228 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2231 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2232 QCOMPARE(o.error(), false);
2233 QCOMPARE(o.invoked(), 14);
2234 QCOMPARE(o.actuals().count(), 1);
2235 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2238 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2239 QCOMPARE(o.error(), false);
2240 QCOMPARE(o.invoked(), 15);
2241 QCOMPARE(o.actuals().count(), 2);
2242 QCOMPARE(o.actuals().at(0), QVariant(4));
2243 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2246 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2247 QCOMPARE(o.error(), false);
2248 QCOMPARE(o.invoked(), 15);
2249 QCOMPARE(o.actuals().count(), 2);
2250 QCOMPARE(o.actuals().at(0), QVariant(8));
2251 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2254 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2255 QCOMPARE(o.error(), false);
2256 QCOMPARE(o.invoked(), 15);
2257 QCOMPARE(o.actuals().count(), 2);
2258 QCOMPARE(o.actuals().at(0), QVariant(3));
2259 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2262 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2263 QCOMPARE(o.error(), false);
2264 QCOMPARE(o.invoked(), 15);
2265 QCOMPARE(o.actuals().count(), 2);
2266 QCOMPARE(o.actuals().at(0), QVariant(44));
2267 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2270 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2271 QCOMPARE(o.error(), false);
2272 QCOMPARE(o.invoked(), -1);
2273 QCOMPARE(o.actuals().count(), 0);
2276 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2277 QCOMPARE(o.error(), false);
2278 QCOMPARE(o.invoked(), 16);
2279 QCOMPARE(o.actuals().count(), 1);
2280 QCOMPARE(o.actuals().at(0), QVariant(10));
2283 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2284 QCOMPARE(o.error(), false);
2285 QCOMPARE(o.invoked(), 17);
2286 QCOMPARE(o.actuals().count(), 2);
2287 QCOMPARE(o.actuals().at(0), QVariant(10));
2288 QCOMPARE(o.actuals().at(1), QVariant(11));
2291 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2292 QCOMPARE(o.error(), false);
2293 QCOMPARE(o.invoked(), 18);
2294 QCOMPARE(o.actuals().count(), 1);
2295 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2298 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2299 QCOMPARE(o.error(), false);
2300 QCOMPARE(o.invoked(), 19);
2301 QCOMPARE(o.actuals().count(), 1);
2302 QCOMPARE(o.actuals().at(0), QVariant(9));
2305 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2306 QCOMPARE(o.error(), false);
2307 QCOMPARE(o.invoked(), 20);
2308 QCOMPARE(o.actuals().count(), 2);
2309 QCOMPARE(o.actuals().at(0), QVariant(10));
2310 QCOMPARE(o.actuals().at(1), QVariant(19));
2313 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2314 QCOMPARE(o.error(), false);
2315 QCOMPARE(o.invoked(), 20);
2316 QCOMPARE(o.actuals().count(), 2);
2317 QCOMPARE(o.actuals().at(0), QVariant(10));
2318 QCOMPARE(o.actuals().at(1), QVariant(13));
2321 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2322 QCOMPARE(o.error(), false);
2323 QCOMPARE(o.invoked(), -3);
2324 QCOMPARE(o.actuals().count(), 1);
2325 QCOMPARE(o.actuals().at(0), QVariant(9));
2328 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2329 QCOMPARE(o.error(), false);
2330 QCOMPARE(o.invoked(), 21);
2331 QCOMPARE(o.actuals().count(), 2);
2332 QCOMPARE(o.actuals().at(0), QVariant(9));
2333 QCOMPARE(o.actuals().at(1), QVariant());
2336 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2337 QCOMPARE(o.error(), false);
2338 QCOMPARE(o.invoked(), 21);
2339 QCOMPARE(o.actuals().count(), 2);
2340 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2341 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2344 // QTBUG-13047 (check that you can pass registered object types as args)
2345 void tst_qdeclarativeecmascript::invokableObjectArg()
2347 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
2349 QObject *o = component.create();
2351 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2353 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2358 // QTBUG-13047 (check that you can return registered object types from methods)
2359 void tst_qdeclarativeecmascript::invokableObjectRet()
2361 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
2363 QObject *o = component.create();
2365 QCOMPARE(o->property("test").toBool(), true);
2370 void tst_qdeclarativeecmascript::listToVariant()
2372 QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
2374 MyQmlContainer container;
2376 QDeclarativeContext context(engine.rootContext());
2377 context.setContextObject(&container);
2379 QObject *object = component.create(&context);
2380 QVERIFY(object != 0);
2382 QVariant v = object->property("test");
2383 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2384 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2390 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2391 void tst_qdeclarativeecmascript::listAssignment()
2393 QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
2394 QObject *obj = component.create();
2395 QCOMPARE(obj->property("list1length").toInt(), 2);
2396 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2397 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2398 QCOMPARE(list1.count(&list1), list2.count(&list2));
2399 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2400 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2405 void tst_qdeclarativeecmascript::multiEngineObject()
2408 obj.setStringProperty("Howdy planet");
2410 QDeclarativeEngine e1;
2411 e1.rootContext()->setContextProperty("thing", &obj);
2412 QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
2414 QDeclarativeEngine e2;
2415 e2.rootContext()->setContextProperty("thing", &obj);
2416 QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
2418 QObject *o1 = c1.create();
2419 QObject *o2 = c2.create();
2421 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2422 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2428 // Test that references to QObjects are cleanup when the object is destroyed
2429 void tst_qdeclarativeecmascript::deletedObject()
2431 QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
2433 QObject *object = component.create();
2435 QCOMPARE(object->property("test1").toBool(), true);
2436 QCOMPARE(object->property("test2").toBool(), true);
2437 QCOMPARE(object->property("test3").toBool(), true);
2438 QCOMPARE(object->property("test4").toBool(), true);
2443 void tst_qdeclarativeecmascript::attachedPropertyScope()
2445 QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
2447 QObject *object = component.create();
2448 QVERIFY(object != 0);
2450 MyQmlAttachedObject *attached =
2451 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2452 QVERIFY(attached != 0);
2454 QCOMPARE(object->property("value2").toInt(), 0);
2456 attached->emitMySignal();
2458 QCOMPARE(object->property("value2").toInt(), 9);
2463 void tst_qdeclarativeecmascript::scriptConnect()
2466 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
2468 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2469 QVERIFY(object != 0);
2471 QCOMPARE(object->property("test").toBool(), false);
2472 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2473 QCOMPARE(object->property("test").toBool(), true);
2479 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
2481 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2482 QVERIFY(object != 0);
2484 QCOMPARE(object->property("test").toBool(), false);
2485 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2486 QCOMPARE(object->property("test").toBool(), true);
2492 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
2494 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2495 QVERIFY(object != 0);
2497 QCOMPARE(object->property("test").toBool(), false);
2498 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2499 QCOMPARE(object->property("test").toBool(), true);
2505 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
2507 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2508 QVERIFY(object != 0);
2510 QCOMPARE(object->methodCalled(), false);
2511 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2512 QCOMPARE(object->methodCalled(), true);
2518 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
2520 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2521 QVERIFY(object != 0);
2523 QCOMPARE(object->methodCalled(), false);
2524 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2525 QCOMPARE(object->methodCalled(), true);
2531 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
2533 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2534 QVERIFY(object != 0);
2536 QCOMPARE(object->property("test").toInt(), 0);
2537 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2538 QCOMPARE(object->property("test").toInt(), 2);
2544 void tst_qdeclarativeecmascript::scriptDisconnect()
2547 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
2549 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2550 QVERIFY(object != 0);
2552 QCOMPARE(object->property("test").toInt(), 0);
2553 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2554 QCOMPARE(object->property("test").toInt(), 1);
2555 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2556 QCOMPARE(object->property("test").toInt(), 2);
2557 emit object->basicSignal();
2558 QCOMPARE(object->property("test").toInt(), 2);
2559 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2560 QCOMPARE(object->property("test").toInt(), 2);
2566 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
2568 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2569 QVERIFY(object != 0);
2571 QCOMPARE(object->property("test").toInt(), 0);
2572 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2573 QCOMPARE(object->property("test").toInt(), 1);
2574 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2575 QCOMPARE(object->property("test").toInt(), 2);
2576 emit object->basicSignal();
2577 QCOMPARE(object->property("test").toInt(), 2);
2578 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2579 QCOMPARE(object->property("test").toInt(), 2);
2585 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
2587 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2588 QVERIFY(object != 0);
2590 QCOMPARE(object->property("test").toInt(), 0);
2591 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2592 QCOMPARE(object->property("test").toInt(), 1);
2593 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2594 QCOMPARE(object->property("test").toInt(), 2);
2595 emit object->basicSignal();
2596 QCOMPARE(object->property("test").toInt(), 2);
2597 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2598 QCOMPARE(object->property("test").toInt(), 3);
2603 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
2605 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2606 QVERIFY(object != 0);
2608 QCOMPARE(object->property("test").toInt(), 0);
2609 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2610 QCOMPARE(object->property("test").toInt(), 1);
2611 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2612 QCOMPARE(object->property("test").toInt(), 2);
2613 emit object->basicSignal();
2614 QCOMPARE(object->property("test").toInt(), 2);
2615 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2616 QCOMPARE(object->property("test").toInt(), 3);
2622 class OwnershipObject : public QObject
2626 OwnershipObject() { object = new QObject; }
2628 QPointer<QObject> object;
2631 QObject *getObject() { return object; }
2634 void tst_qdeclarativeecmascript::ownership()
2636 OwnershipObject own;
2637 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2638 context->setContextObject(&own);
2641 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2643 QVERIFY(own.object != 0);
2645 QObject *object = component.create(context);
2647 engine.collectGarbage();
2649 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2650 QCoreApplication::processEvents();
2652 QVERIFY(own.object == 0);
2657 own.object = new QObject(&own);
2660 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2662 QVERIFY(own.object != 0);
2664 QObject *object = component.create(context);
2666 engine.collectGarbage();
2668 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2669 QCoreApplication::processEvents();
2671 QVERIFY(own.object != 0);
2679 class CppOwnershipReturnValue : public QObject
2683 CppOwnershipReturnValue() : value(0) {}
2684 ~CppOwnershipReturnValue() { delete value; }
2686 Q_INVOKABLE QObject *create() {
2687 value = new QObject;
2688 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2692 Q_INVOKABLE MyQmlObject *createQmlObject() {
2693 MyQmlObject *rv = new MyQmlObject;
2698 QPointer<QObject> value;
2702 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2703 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2705 CppOwnershipReturnValue source;
2708 QDeclarativeEngine engine;
2709 engine.rootContext()->setContextProperty("source", &source);
2711 QVERIFY(source.value == 0);
2713 QDeclarativeComponent component(&engine);
2714 component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2716 QObject *object = component.create();
2718 QVERIFY(object != 0);
2719 QVERIFY(source.value != 0);
2724 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2725 QCoreApplication::processEvents();
2727 QVERIFY(source.value != 0);
2731 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2733 CppOwnershipReturnValue source;
2736 QDeclarativeEngine engine;
2737 engine.rootContext()->setContextProperty("source", &source);
2739 QVERIFY(source.value == 0);
2741 QDeclarativeComponent component(&engine);
2742 component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2744 QObject *object = component.create();
2746 QVERIFY(object != 0);
2747 QVERIFY(source.value != 0);
2752 engine.collectGarbage();
2753 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2754 QCoreApplication::processEvents();
2756 QVERIFY(source.value == 0);
2759 class QListQObjectMethodsObject : public QObject
2763 QListQObjectMethodsObject() {
2764 m_objects.append(new MyQmlObject());
2765 m_objects.append(new MyQmlObject());
2768 ~QListQObjectMethodsObject() {
2769 qDeleteAll(m_objects);
2773 QList<QObject *> getObjects() { return m_objects; }
2776 QList<QObject *> m_objects;
2779 // Tests that returning a QList<QObject*> from a method works
2780 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2782 QListQObjectMethodsObject obj;
2783 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2784 context->setContextObject(&obj);
2786 QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
2788 QObject *object = component.create(context);
2790 QCOMPARE(object->property("test").toInt(), 2);
2791 QCOMPARE(object->property("test2").toBool(), true);
2798 void tst_qdeclarativeecmascript::strictlyEquals()
2800 QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
2802 QObject *object = component.create();
2803 QVERIFY(object != 0);
2805 QCOMPARE(object->property("test1").toBool(), true);
2806 QCOMPARE(object->property("test2").toBool(), true);
2807 QCOMPARE(object->property("test3").toBool(), true);
2808 QCOMPARE(object->property("test4").toBool(), true);
2809 QCOMPARE(object->property("test5").toBool(), true);
2810 QCOMPARE(object->property("test6").toBool(), true);
2811 QCOMPARE(object->property("test7").toBool(), true);
2812 QCOMPARE(object->property("test8").toBool(), true);
2817 void tst_qdeclarativeecmascript::compiled()
2819 QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
2821 QObject *object = component.create();
2822 QVERIFY(object != 0);
2824 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2825 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2826 QCOMPARE(object->property("test3").toBool(), true);
2827 QCOMPARE(object->property("test4").toBool(), false);
2828 QCOMPARE(object->property("test5").toBool(), false);
2829 QCOMPARE(object->property("test6").toBool(), true);
2831 QCOMPARE(object->property("test7").toInt(), 185);
2832 QCOMPARE(object->property("test8").toInt(), 167);
2833 QCOMPARE(object->property("test9").toBool(), true);
2834 QCOMPARE(object->property("test10").toBool(), false);
2835 QCOMPARE(object->property("test11").toBool(), false);
2836 QCOMPARE(object->property("test12").toBool(), true);
2838 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2839 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2840 QCOMPARE(object->property("test15").toBool(), false);
2841 QCOMPARE(object->property("test16").toBool(), true);
2843 QCOMPARE(object->property("test17").toInt(), 5);
2844 QCOMPARE(object->property("test18").toReal(), qreal(176));
2845 QCOMPARE(object->property("test19").toInt(), 7);
2846 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2847 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2848 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2849 QCOMPARE(object->property("test23").toBool(), true);
2850 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2851 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2856 // Test that numbers assigned in bindings as strings work consistently
2857 void tst_qdeclarativeecmascript::numberAssignment()
2859 QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
2861 QObject *object = component.create();
2862 QVERIFY(object != 0);
2864 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2865 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2866 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2867 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2868 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2870 QCOMPARE(object->property("test5"), QVariant((int)7));
2871 QCOMPARE(object->property("test6"), QVariant((int)7));
2872 QCOMPARE(object->property("test7"), QVariant((int)6));
2873 QCOMPARE(object->property("test8"), QVariant((int)6));
2875 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2876 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2877 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2878 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2883 void tst_qdeclarativeecmascript::propertySplicing()
2885 QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
2887 QObject *object = component.create();
2888 QVERIFY(object != 0);
2890 QCOMPARE(object->property("test").toBool(), true);
2896 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2898 QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
2900 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2901 QVERIFY(object != 0);
2903 MyQmlObject::MyType type;
2904 type.value = 0x8971123;
2905 emit object->signalWithUnknownType(type);
2907 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2909 QCOMPARE(result.value, type.value);
2915 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2917 QTest::addColumn<QString>("expression");
2918 QTest::addColumn<QString>("compare");
2920 QString compareStrict("(function(a, b) { return a === b; })");
2921 QTest::newRow("true") << "true" << compareStrict;
2922 QTest::newRow("undefined") << "undefined" << compareStrict;
2923 QTest::newRow("null") << "null" << compareStrict;
2924 QTest::newRow("123") << "123" << compareStrict;
2925 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2927 QString comparePropertiesStrict(
2929 " if (typeof b != 'object')"
2931 " var props = Object.getOwnPropertyNames(b);"
2932 " for (var i = 0; i < props.length; ++i) {"
2933 " var p = props[i];"
2934 " return arguments.callee(a[p], b[p]);"
2937 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2938 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2941 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2943 QFETCH(QString, expression);
2944 QFETCH(QString, compare);
2946 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2947 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2948 QVERIFY(object != 0);
2950 QJSValue value = engine.evaluate(expression);
2951 QVERIFY(!engine.hasUncaughtException());
2952 object->setProperty("expression", expression);
2953 object->setProperty("compare", compare);
2954 object->setProperty("pass", false);
2956 emit object->signalWithVariant(QVariant::fromValue(value));
2957 QVERIFY(object->property("pass").toBool());
2960 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2962 signalWithJSValueInVariant_data();
2965 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2967 QFETCH(QString, expression);
2968 QFETCH(QString, compare);
2970 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2971 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2972 QVERIFY(object != 0);
2975 QJSValue value = engine2.evaluate(expression);
2976 QVERIFY(!engine2.hasUncaughtException());
2977 object->setProperty("expression", expression);
2978 object->setProperty("compare", compare);
2979 object->setProperty("pass", false);
2981 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2982 emit object->signalWithVariant(QVariant::fromValue(value));
2983 QVERIFY(!object->property("pass").toBool());
2986 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2988 signalWithJSValueInVariant_data();
2991 void tst_qdeclarativeecmascript::signalWithQJSValue()
2993 QFETCH(QString, expression);
2994 QFETCH(QString, compare);
2996 QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
2997 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2998 QVERIFY(object != 0);
3000 QJSValue value = engine.evaluate(expression);
3001 QVERIFY(!engine.hasUncaughtException());
3002 object->setProperty("expression", expression);
3003 object->setProperty("compare", compare);
3004 object->setProperty("pass", false);
3006 emit object->signalWithQJSValue(value);
3008 QVERIFY(object->property("pass").toBool());
3009 QVERIFY(object->qjsvalue().strictlyEquals(value));
3012 void tst_qdeclarativeecmascript::moduleApi_data()
3014 QTest::addColumn<QUrl>("testfile");
3015 QTest::addColumn<QString>("errorMessage");
3016 QTest::addColumn<QStringList>("warningMessages");
3017 QTest::addColumn<QStringList>("readProperties");
3018 QTest::addColumn<QVariantList>("readExpectedValues");
3019 QTest::addColumn<QStringList>("writeProperties");
3020 QTest::addColumn<QVariantList>("writeValues");
3021 QTest::addColumn<QStringList>("readBackProperties");
3022 QTest::addColumn<QVariantList>("readBackExpectedValues");
3024 QTest::newRow("qobject, register + read + method")
3025 << testFileUrl("moduleapi/qobjectModuleApi.qml")
3028 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
3029 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
3030 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
3036 QTest::newRow("script, register + read")
3037 << testFileUrl("moduleapi/scriptModuleApi.qml")
3040 << (QStringList() << "scriptTest")
3041 << (QVariantList() << 13)
3047 QTest::newRow("qobject, caching + read")
3048 << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
3051 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3052 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3058 QTest::newRow("script, caching + read")
3059 << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
3062 << (QStringList() << "scriptTest")
3063 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3069 QTest::newRow("qobject, writing + readonly constraints")
3070 << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
3072 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3073 << (QStringList() << "readOnlyProperty" << "writableProperty")
3074 << (QVariantList() << 20 << 50)
3075 << (QStringList() << "firstProperty" << "writableProperty")
3076 << (QVariantList() << 30 << 30)
3077 << (QStringList() << "readOnlyProperty" << "writableProperty")
3078 << (QVariantList() << 20 << 30);
3080 QTest::newRow("script, writing + readonly constraints")
3081 << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
3083 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3084 << (QStringList() << "readBack" << "unchanged")
3085 << (QVariantList() << 13 << 42)
3086 << (QStringList() << "firstProperty" << "secondProperty")
3087 << (QVariantList() << 30 << 30)
3088 << (QStringList() << "readBack" << "unchanged")
3089 << (QVariantList() << 30 << 42);
3091 QTest::newRow("qobject module API enum values in JS")
3092 << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
3095 << (QStringList() << "enumValue" << "enumMethod")
3096 << (QVariantList() << 42 << 30)
3102 QTest::newRow("qobject, invalid major version fail")
3103 << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
3104 << QString("QDeclarativeComponent: Component is not ready")
3113 QTest::newRow("qobject, invalid minor version fail")
3114 << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
3115 << QString("QDeclarativeComponent: Component is not ready")
3125 void tst_qdeclarativeecmascript::moduleApi()
3127 QFETCH(QUrl, testfile);
3128 QFETCH(QString, errorMessage);
3129 QFETCH(QStringList, warningMessages);
3130 QFETCH(QStringList, readProperties);
3131 QFETCH(QVariantList, readExpectedValues);
3132 QFETCH(QStringList, writeProperties);
3133 QFETCH(QVariantList, writeValues);
3134 QFETCH(QStringList, readBackProperties);
3135 QFETCH(QVariantList, readBackExpectedValues);
3137 QDeclarativeComponent component(&engine, testfile);
3139 if (!errorMessage.isEmpty())
3140 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3142 if (warningMessages.size())
3143 foreach (const QString &warning, warningMessages)
3144 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3146 QObject *object = component.create();
3147 if (!errorMessage.isEmpty()) {
3148 QVERIFY(object == 0);
3150 QVERIFY(object != 0);
3151 for (int i = 0; i < readProperties.size(); ++i)
3152 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3153 for (int i = 0; i < writeProperties.size(); ++i)
3154 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3155 for (int i = 0; i < readBackProperties.size(); ++i)
3156 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3161 void tst_qdeclarativeecmascript::importScripts_data()
3163 QTest::addColumn<QUrl>("testfile");
3164 QTest::addColumn<QString>("errorMessage");
3165 QTest::addColumn<QStringList>("warningMessages");
3166 QTest::addColumn<QStringList>("propertyNames");
3167 QTest::addColumn<QVariantList>("propertyValues");
3169 QTest::newRow("basic functionality")
3170 << testFileUrl("jsimport/testImport.qml")
3173 << (QStringList() << QLatin1String("importedScriptStringValue")
3174 << QLatin1String("importedScriptFunctionValue")
3175 << QLatin1String("importedModuleAttachedPropertyValue")
3176 << QLatin1String("importedModuleEnumValue"))
3177 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3182 QTest::newRow("import scoping")
3183 << testFileUrl("jsimport/testImportScoping.qml")
3186 << (QStringList() << QLatin1String("componentError"))
3187 << (QVariantList() << QVariant(5));
3189 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3190 << testFileUrl("jsimportfail/failOne.qml")
3192 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3193 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3194 << (QVariantList() << QVariant(QString()));
3196 QTest::newRow("javascript imports in an import should be private to the import scope")
3197 << testFileUrl("jsimportfail/failTwo.qml")
3199 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3200 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3201 << (QVariantList() << QVariant(QString()));
3203 QTest::newRow("module imports in an import should be private to the import scope")
3204 << testFileUrl("jsimportfail/failThree.qml")
3206 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3207 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3208 << (QVariantList() << QVariant(false));
3210 QTest::newRow("typenames in an import should be private to the import scope")
3211 << testFileUrl("jsimportfail/failFour.qml")
3213 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3214 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3215 << (QVariantList() << QVariant(0));
3217 QTest::newRow("import with imports has it's own activation scope")
3218 << testFileUrl("jsimportfail/failFive.qml")
3220 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component")))
3221 << (QStringList() << QLatin1String("componentError"))
3222 << (QVariantList() << QVariant(0));
3224 QTest::newRow("import pragma library script")
3225 << testFileUrl("jsimport/testImportPragmaLibrary.qml")
3228 << (QStringList() << QLatin1String("testValue"))
3229 << (QVariantList() << QVariant(31));
3231 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3232 << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
3234 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3235 << (QStringList() << QLatin1String("testValue"))
3236 << (QVariantList() << QVariant(0));
3238 QTest::newRow("import pragma library script which has an import")
3239 << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
3242 << (QStringList() << QLatin1String("testValue"))
3243 << (QVariantList() << QVariant(55));
3245 QTest::newRow("import pragma library script which has a pragma library import")
3246 << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3249 << (QStringList() << QLatin1String("testValue"))
3250 << (QVariantList() << QVariant(18));
3253 void tst_qdeclarativeecmascript::importScripts()
3255 QFETCH(QUrl, testfile);
3256 QFETCH(QString, errorMessage);
3257 QFETCH(QStringList, warningMessages);
3258 QFETCH(QStringList, propertyNames);
3259 QFETCH(QVariantList, propertyValues);
3261 QDeclarativeComponent component(&engine, testfile);
3263 if (!errorMessage.isEmpty())
3264 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3266 if (warningMessages.size())
3267 foreach (const QString &warning, warningMessages)
3268 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3270 QObject *object = component.create();
3271 if (!errorMessage.isEmpty()) {
3272 QVERIFY(object == 0);
3274 QVERIFY(object != 0);
3275 for (int i = 0; i < propertyNames.size(); ++i)
3276 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3281 void tst_qdeclarativeecmascript::scarceResources_other()
3283 /* These tests require knowledge of state, since we test values after
3284 performing signal or function invocation. */
3286 QPixmap origPixmap(100, 100);
3287 origPixmap.fill(Qt::blue);
3288 QString srp_name, expectedWarning;
3289 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3290 ScarceResourceObject *eo = 0;
3292 QObject *object = 0;
3294 /* property var semantics */
3296 // test that scarce resources are handled properly in signal invocation
3297 QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
3298 object = varComponentTen.create();
3299 srsc = object->findChild<QObject*>("srsc");
3301 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3302 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3303 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3304 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3305 QMetaObject::invokeMethod(srsc, "testSignal");
3306 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3307 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3308 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3309 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3310 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3311 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3312 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3313 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3314 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3315 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3318 // test that scarce resources are handled properly from js functions in qml files
3319 QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
3320 object = varComponentEleven.create();
3321 QVERIFY(object != 0);
3322 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3323 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3324 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3325 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3326 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3327 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3328 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3329 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3330 QMetaObject::invokeMethod(object, "releaseScarceResource");
3331 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3332 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3333 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3334 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3337 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3338 QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
3339 object = varComponentTwelve.create();
3340 QVERIFY(object != 0);
3341 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3342 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3343 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3344 srp_name = object->property("srp_name").toString();
3345 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3346 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3347 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3348 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3349 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3350 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3351 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3354 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3355 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3356 QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
3357 object = varComponentThirteen.create();
3358 QVERIFY(object != 0);
3359 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3360 QMetaObject::invokeMethod(object, "assignVarProperty");
3361 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3362 QMetaObject::invokeMethod(object, "deassignVarProperty");
3363 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3366 /* property variant semantics */
3368 // test that scarce resources are handled properly in signal invocation
3369 QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
3370 object = variantComponentTen.create();
3371 QVERIFY(object != 0);
3372 srsc = object->findChild<QObject*>("srsc");
3374 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3375 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3376 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3377 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3378 QMetaObject::invokeMethod(srsc, "testSignal");
3379 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3380 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3381 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3382 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3383 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3384 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3385 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3386 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3387 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3388 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3391 // test that scarce resources are handled properly from js functions in qml files
3392 QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
3393 object = variantComponentEleven.create();
3394 QVERIFY(object != 0);
3395 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3396 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3397 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3398 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3399 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3400 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3401 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3402 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3403 QMetaObject::invokeMethod(object, "releaseScarceResource");
3404 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3405 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3406 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3407 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3410 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3411 QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
3412 object = variantComponentTwelve.create();
3413 QVERIFY(object != 0);
3414 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3415 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3416 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3417 srp_name = object->property("srp_name").toString();
3418 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3419 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3420 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3421 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3422 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3423 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3424 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3428 void tst_qdeclarativeecmascript::scarceResources_data()
3430 QTest::addColumn<QUrl>("qmlFile");
3431 QTest::addColumn<bool>("readDetachStatus");
3432 QTest::addColumn<bool>("expectedDetachStatus");
3433 QTest::addColumn<QStringList>("propertyNames");
3434 QTest::addColumn<QVariantList>("expectedValidity");
3435 QTest::addColumn<QVariantList>("expectedValues");
3436 QTest::addColumn<QStringList>("expectedErrors");
3438 QPixmap origPixmap(100, 100);
3439 origPixmap.fill(Qt::blue);
3441 /* property var semantics */
3443 // in the following three cases, the instance created from the component
3444 // has a property which is a copy of the scarce resource; hence, the
3445 // resource should NOT be detached prior to deletion of the object instance,
3446 // unless the resource is destroyed explicitly.
3447 QTest::newRow("var: import scarce resource copy directly")
3448 << testFileUrl("scarceResourceCopy.var.qml")
3450 << false // won't be detached, because assigned to property and not explicitly released
3451 << (QStringList() << QLatin1String("scarceResourceCopy"))
3452 << (QList<QVariant>() << true)
3453 << (QList<QVariant>() << origPixmap)
3456 QTest::newRow("var: import scarce resource copy from JS")
3457 << testFileUrl("scarceResourceCopyFromJs.var.qml")
3459 << false // won't be detached, because assigned to property and not explicitly released
3460 << (QStringList() << QLatin1String("scarceResourceCopy"))
3461 << (QList<QVariant>() << true)
3462 << (QList<QVariant>() << origPixmap)
3465 QTest::newRow("var: import released scarce resource copy from JS")
3466 << testFileUrl("scarceResourceDestroyedCopy.var.qml")
3468 << true // explicitly released, so it will be detached
3469 << (QStringList() << QLatin1String("scarceResourceCopy"))
3470 << (QList<QVariant>() << false)
3471 << (QList<QVariant>() << QVariant())
3474 // in the following three cases, no other copy should exist in memory,
3475 // and so it should be detached (unless explicitly preserved).
3476 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3477 << testFileUrl("scarceResourceTest.var.qml")
3479 << true // auto released, so it will be detached
3480 << (QStringList() << QLatin1String("scarceResourceTest"))
3481 << (QList<QVariant>() << true)
3482 << (QList<QVariant>() << QVariant(100))
3484 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3485 << testFileUrl("scarceResourceTestPreserve.var.qml")
3487 << false // won't be detached because we explicitly preserve it
3488 << (QStringList() << QLatin1String("scarceResourceTest"))
3489 << (QList<QVariant>() << true)
3490 << (QList<QVariant>() << QVariant(100))
3492 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3493 << testFileUrl("scarceResourceTestMultiple.var.qml")
3495 << true // will be detached because all resources were released manually or automatically.
3496 << (QStringList() << QLatin1String("scarceResourceTest"))
3497 << (QList<QVariant>() << true)
3498 << (QList<QVariant>() << QVariant(100))
3501 // In the following three cases, test that scarce resources are handled
3502 // correctly for imports.
3503 QTest::newRow("var: import with no binding")
3504 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3505 << false // cannot check detach status.
3508 << QList<QVariant>()
3509 << QList<QVariant>()
3511 QTest::newRow("var: import with binding without explicit preserve")
3512 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3515 << (QStringList() << QLatin1String("scarceResourceCopy"))
3516 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3517 << (QList<QVariant>() << QVariant())
3519 QTest::newRow("var: import with explicit release after binding evaluation")
3520 << testFileUrl("scarceResourceCopyImport.var.qml")
3523 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3524 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3525 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3527 QTest::newRow("var: import with different js objects")
3528 << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
3531 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3532 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3533 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3535 QTest::newRow("var: import with different js objects and explicit release")
3536 << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
3539 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3540 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3541 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3543 QTest::newRow("var: import with same js objects and explicit release")
3544 << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
3547 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3548 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3549 << (QList<QVariant>() << QVariant() << QVariant())
3551 QTest::newRow("var: binding with same js objects and explicit release")
3552 << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
3555 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3556 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3557 << (QList<QVariant>() << QVariant() << QVariant())
3561 /* property variant semantics */
3563 // in the following three cases, the instance created from the component
3564 // has a property which is a copy of the scarce resource; hence, the
3565 // resource should NOT be detached prior to deletion of the object instance,
3566 // unless the resource is destroyed explicitly.
3567 QTest::newRow("variant: import scarce resource copy directly")
3568 << testFileUrl("scarceResourceCopy.variant.qml")
3570 << false // won't be detached, because assigned to property and not explicitly released
3571 << (QStringList() << QLatin1String("scarceResourceCopy"))
3572 << (QList<QVariant>() << true)
3573 << (QList<QVariant>() << origPixmap)
3576 QTest::newRow("variant: import scarce resource copy from JS")
3577 << testFileUrl("scarceResourceCopyFromJs.variant.qml")
3579 << false // won't be detached, because assigned to property and not explicitly released
3580 << (QStringList() << QLatin1String("scarceResourceCopy"))
3581 << (QList<QVariant>() << true)
3582 << (QList<QVariant>() << origPixmap)
3585 QTest::newRow("variant: import released scarce resource copy from JS")
3586 << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
3588 << true // explicitly released, so it will be detached
3589 << (QStringList() << QLatin1String("scarceResourceCopy"))
3590 << (QList<QVariant>() << false)
3591 << (QList<QVariant>() << QVariant())
3594 // in the following three cases, no other copy should exist in memory,
3595 // and so it should be detached (unless explicitly preserved).
3596 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3597 << testFileUrl("scarceResourceTest.variant.qml")
3599 << true // auto released, so it will be detached
3600 << (QStringList() << QLatin1String("scarceResourceTest"))
3601 << (QList<QVariant>() << true)
3602 << (QList<QVariant>() << QVariant(100))
3604 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3605 << testFileUrl("scarceResourceTestPreserve.variant.qml")
3607 << false // won't be detached because we explicitly preserve it
3608 << (QStringList() << QLatin1String("scarceResourceTest"))
3609 << (QList<QVariant>() << true)
3610 << (QList<QVariant>() << QVariant(100))
3612 QTest::newRow("variant: import multiple scarce resources")
3613 << testFileUrl("scarceResourceTestMultiple.variant.qml")
3615 << true // will be detached because all resources were released manually or automatically.
3616 << (QStringList() << QLatin1String("scarceResourceTest"))
3617 << (QList<QVariant>() << true)
3618 << (QList<QVariant>() << QVariant(100))
3621 // In the following three cases, test that scarce resources are handled
3622 // correctly for imports.
3623 QTest::newRow("variant: import with no binding")
3624 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3625 << false // cannot check detach status.
3628 << QList<QVariant>()
3629 << QList<QVariant>()
3631 QTest::newRow("variant: import with binding without explicit preserve")
3632 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3635 << (QStringList() << QLatin1String("scarceResourceCopy"))
3636 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3637 << (QList<QVariant>() << QVariant())
3639 QTest::newRow("variant: import with explicit release after binding evaluation")
3640 << testFileUrl("scarceResourceCopyImport.variant.qml")
3643 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3644 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3645 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3649 void tst_qdeclarativeecmascript::scarceResources()
3651 QFETCH(QUrl, qmlFile);
3652 QFETCH(bool, readDetachStatus);
3653 QFETCH(bool, expectedDetachStatus);
3654 QFETCH(QStringList, propertyNames);
3655 QFETCH(QVariantList, expectedValidity);
3656 QFETCH(QVariantList, expectedValues);
3657 QFETCH(QStringList, expectedErrors);
3659 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3660 ScarceResourceObject *eo = 0;
3661 QObject *object = 0;
3663 QDeclarativeComponent c(&engine, qmlFile);
3664 object = c.create();
3665 QVERIFY(object != 0);
3666 for (int i = 0; i < propertyNames.size(); ++i) {
3667 QString prop = propertyNames.at(i);
3668 bool validity = expectedValidity.at(i).toBool();
3669 QVariant value = expectedValues.at(i);
3671 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3672 if (value.type() == QVariant::Int) {
3673 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3674 } else if (value.type() == QVariant::Pixmap) {
3675 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3679 if (readDetachStatus) {
3680 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3681 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3684 QVERIFY(ep->scarceResources.isEmpty());
3688 void tst_qdeclarativeecmascript::propertyChangeSlots()
3690 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3691 QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
3692 QObject *object = component.create();
3693 QVERIFY(object != 0);
3696 // ensure that invalid property names fail properly.
3697 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3698 QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
3699 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3700 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3701 object = e1.create();
3702 QVERIFY(object == 0);
3705 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3706 QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
3707 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3708 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3709 object = e2.create();
3710 QVERIFY(object == 0);
3713 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3714 QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
3715 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3716 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3717 object = e3.create();
3718 QVERIFY(object == 0);
3721 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3722 QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
3723 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3724 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3725 object = e4.create();
3726 QVERIFY(object == 0);
3730 void tst_qdeclarativeecmascript::propertyVar_data()
3732 QTest::addColumn<QUrl>("qmlFile");
3735 QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
3736 QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
3737 QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
3738 QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
3739 QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
3740 QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
3741 QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
3742 QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
3743 QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
3744 QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
3747 void tst_qdeclarativeecmascript::propertyVar()
3749 QFETCH(QUrl, qmlFile);
3751 QDeclarativeComponent component(&engine, qmlFile);
3752 QObject *object = component.create();
3753 QVERIFY(object != 0);
3755 QCOMPARE(object->property("test").toBool(), true);
3760 // Tests that we can write QVariant values to var properties from C++
3761 void tst_qdeclarativeecmascript::propertyVarCpp()
3763 QObject *object = 0;
3765 // ensure that writing to and reading from a var property from cpp works as required.
3766 // Literal values stored in var properties can be read and written as QVariants
3767 // of a specific type, whereas object values are read as QVariantMaps.
3768 QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
3769 object = component.create();
3770 QVERIFY(object != 0);
3771 // assign int to property var that currently has int assigned
3772 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3773 QCOMPARE(object->property("varBound"), QVariant(15));
3774 QCOMPARE(object->property("intBound"), QVariant(15));
3775 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3776 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3777 // assign string to property var that current has bool assigned
3778 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3779 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3780 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3781 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3782 // now enforce behaviour when accessing JavaScript objects from cpp.
3783 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3787 static void gc(QDeclarativeEngine &engine)
3789 engine.collectGarbage();
3790 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
3791 QCoreApplication::processEvents();
3794 void tst_qdeclarativeecmascript::propertyVarOwnership()
3796 // Referenced JS objects are not collected
3798 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
3799 QObject *object = component.create();
3800 QVERIFY(object != 0);
3801 QCOMPARE(object->property("test").toBool(), false);
3802 QMetaObject::invokeMethod(object, "runTest");
3803 QCOMPARE(object->property("test").toBool(), true);
3806 // Referenced JS objects are not collected
3808 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
3809 QObject *object = component.create();
3810 QVERIFY(object != 0);
3811 QCOMPARE(object->property("test").toBool(), false);
3812 QMetaObject::invokeMethod(object, "runTest");
3813 QCOMPARE(object->property("test").toBool(), true);
3816 // Qt objects are not collected until they've been dereferenced
3818 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
3819 QObject *object = component.create();
3820 QVERIFY(object != 0);
3822 QCOMPARE(object->property("test2").toBool(), false);
3823 QCOMPARE(object->property("test2").toBool(), false);
3825 QMetaObject::invokeMethod(object, "runTest");
3826 QCOMPARE(object->property("test1").toBool(), true);
3828 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3829 QVERIFY(!referencedObject.isNull());
3831 QVERIFY(!referencedObject.isNull());
3833 QMetaObject::invokeMethod(object, "runTest2");
3834 QCOMPARE(object->property("test2").toBool(), true);
3836 QVERIFY(referencedObject.isNull());
3840 // Self reference does not prevent Qt object collection
3842 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
3843 QObject *object = component.create();
3844 QVERIFY(object != 0);
3846 QCOMPARE(object->property("test").toBool(), true);
3848 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3849 QVERIFY(!referencedObject.isNull());
3851 QVERIFY(!referencedObject.isNull());
3853 QMetaObject::invokeMethod(object, "runTest");
3855 QVERIFY(referencedObject.isNull());
3861 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3863 // The childObject has a reference to a different QObject. We want to ensure
3864 // that the different item will not be cleaned up until required. IE, the childObject
3865 // has implicit ownership of the constructed QObject.
3866 QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
3867 QObject *object = component.create();
3868 QVERIFY(object != 0);
3869 QMetaObject::invokeMethod(object, "assignCircular");
3870 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3871 QCoreApplication::processEvents();
3872 QObject *rootObject = object->property("vp").value<QObject*>();
3873 QVERIFY(rootObject != 0);
3874 QObject *childObject = rootObject->findChild<QObject*>("text");
3875 QVERIFY(childObject != 0);
3876 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3877 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3878 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3879 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3880 QVERIFY(!qobjectGuard.isNull());
3881 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3882 QCoreApplication::processEvents();
3883 QVERIFY(!qobjectGuard.isNull());
3884 QMetaObject::invokeMethod(object, "deassignCircular");
3885 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3886 QCoreApplication::processEvents();
3887 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3891 void tst_qdeclarativeecmascript::propertyVarReparent()
3893 // ensure that nothing breaks if we re-parent objects
3894 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3895 QObject *object = component.create();
3896 QVERIFY(object != 0);
3897 QMetaObject::invokeMethod(object, "assignVarProp");
3898 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3899 QCoreApplication::processEvents();
3900 QObject *rect = object->property("vp").value<QObject*>();
3901 QObject *text = rect->findChild<QObject*>("textOne");
3902 QObject *text2 = rect->findChild<QObject*>("textTwo");
3903 QWeakPointer<QObject> rectGuard(rect);
3904 QWeakPointer<QObject> textGuard(text);
3905 QWeakPointer<QObject> text2Guard(text2);
3906 QVERIFY(!rectGuard.isNull());
3907 QVERIFY(!textGuard.isNull());
3908 QVERIFY(!text2Guard.isNull());
3909 QCOMPARE(text->property("textCanary").toInt(), 11);
3910 QCOMPARE(text2->property("textCanary").toInt(), 12);
3911 // now construct an image which we will reparent.
3912 QMetaObject::invokeMethod(text2, "constructQObject");
3913 QObject *image = text2->property("vp").value<QObject*>();
3914 QWeakPointer<QObject> imageGuard(image);
3915 QVERIFY(!imageGuard.isNull());
3916 QCOMPARE(image->property("imageCanary").toInt(), 13);
3917 // now reparent the "Image" object (currently, it has JS ownership)
3918 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3919 QMetaObject::invokeMethod(text2, "deassignVp");
3920 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3921 QCoreApplication::processEvents();
3922 QCOMPARE(text->property("textCanary").toInt(), 11);
3923 QCOMPARE(text2->property("textCanary").toInt(), 22);
3924 QVERIFY(!imageGuard.isNull()); // should still be alive.
3925 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3926 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3927 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3928 QCoreApplication::processEvents();
3929 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3933 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3935 // sometimes reparenting can cause problems
3936 // (eg, if the ctxt is collected, varproperties are no longer available)
3937 // this test ensures that no crash occurs in that situation.
3938 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3939 QObject *object = component.create();
3940 QVERIFY(object != 0);
3941 QMetaObject::invokeMethod(object, "assignVarProp");
3942 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3943 QCoreApplication::processEvents();
3944 QObject *rect = object->property("vp").value<QObject*>();
3945 QObject *text = rect->findChild<QObject*>("textOne");
3946 QObject *text2 = rect->findChild<QObject*>("textTwo");
3947 QWeakPointer<QObject> rectGuard(rect);
3948 QWeakPointer<QObject> textGuard(text);
3949 QWeakPointer<QObject> text2Guard(text2);
3950 QVERIFY(!rectGuard.isNull());
3951 QVERIFY(!textGuard.isNull());
3952 QVERIFY(!text2Guard.isNull());
3953 QCOMPARE(text->property("textCanary").toInt(), 11);
3954 QCOMPARE(text2->property("textCanary").toInt(), 12);
3955 // now construct an image which we will reparent.
3956 QMetaObject::invokeMethod(text2, "constructQObject");
3957 QObject *image = text2->property("vp").value<QObject*>();
3958 QWeakPointer<QObject> imageGuard(image);
3959 QVERIFY(!imageGuard.isNull());
3960 QCOMPARE(image->property("imageCanary").toInt(), 13);
3961 // now reparent the "Image" object (currently, it has JS ownership)
3962 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3963 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3964 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3965 QCoreApplication::processEvents();
3966 QVERIFY(!imageGuard.isNull()); // should still be alive.
3967 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3969 QVERIFY(imageGuard.isNull()); // should now be dead.
3972 void tst_qdeclarativeecmascript::propertyVarCircular()
3974 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3975 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
3976 QObject *object = component.create();
3977 QVERIFY(object != 0);
3978 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3979 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3980 QCoreApplication::processEvents();
3981 QCOMPARE(object->property("canaryInt"), QVariant(5));
3982 QVariant canaryResourceVariant = object->property("canaryResource");
3983 QVERIFY(canaryResourceVariant.isValid());
3984 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3985 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3986 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3987 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3988 QCoreApplication::processEvents();
3989 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3990 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3991 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3992 QCoreApplication::processEvents();
3993 QCOMPARE(object->property("canaryInt"), QVariant(2));
3994 QCOMPARE(object->property("canaryResource"), QVariant(1));
3995 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3999 void tst_qdeclarativeecmascript::propertyVarCircular2()
4001 // track deletion of JS-owned parent item with Cpp-owned child
4002 // where the child has a var property referencing its parent.
4003 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4004 QObject *object = component.create();
4005 QVERIFY(object != 0);
4006 QMetaObject::invokeMethod(object, "assignCircular");
4007 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4008 QCoreApplication::processEvents();
4009 QObject *rootObject = object->property("vp").value<QObject*>();
4010 QVERIFY(rootObject != 0);
4011 QObject *childObject = rootObject->findChild<QObject*>("text");
4012 QVERIFY(childObject != 0);
4013 QWeakPointer<QObject> rootObjectTracker(rootObject);
4014 QVERIFY(!rootObjectTracker.isNull());
4015 QWeakPointer<QObject> childObjectTracker(childObject);
4016 QVERIFY(!childObjectTracker.isNull());
4018 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4019 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4020 QMetaObject::invokeMethod(object, "deassignCircular");
4021 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4022 QCoreApplication::processEvents();
4023 QVERIFY(rootObjectTracker.isNull()); // should have been collected
4024 QVERIFY(childObjectTracker.isNull()); // should have been collected
4028 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
4030 *(int*)(parameter) += 1;
4031 qPersistentDispose(object);
4034 void tst_qdeclarativeecmascript::propertyVarInheritance()
4036 int propertyVarWeakRefCallbackCount = 0;
4038 // enforce behaviour regarding element inheritance - ensure handle disposal.
4039 // The particular component under test here has a chain of references.
4040 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
4041 QObject *object = component.create();
4042 QVERIFY(object != 0);
4043 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
4044 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4045 QCoreApplication::processEvents();
4046 // we want to be able to track when the varProperties array of the last metaobject is disposed
4047 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
4048 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*>();
4049 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
4050 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
4051 v8::Persistent<v8::Value> icoCanaryHandle;
4052 v8::Persistent<v8::Value> ccoCanaryHandle;
4055 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4056 // public function which can return us a handle to something in the varProperties array.
4057 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4058 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4059 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4060 // as the varproperties array of each vmemo still references the resource.
4061 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4062 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4064 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4066 // now we deassign the var prop, which should trigger collection of item subtrees.
4067 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4068 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4069 QCoreApplication::processEvents();
4070 // ensure that there are only weak handles to the underlying varProperties array remaining.
4072 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4074 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4075 // to what remains are weak, all varProperties arrays must have been collected.
4078 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4080 int propertyVarWeakRefCallbackCount = 0;
4082 // The particular component under test here does NOT have a chain of references; the
4083 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4084 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4085 QObject *object = component.create();
4086 QVERIFY(object != 0);
4087 QMetaObject::invokeMethod(object, "assignCircular");
4088 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4089 QCoreApplication::processEvents();
4090 QObject *rootObject = object->property("vp").value<QObject*>();
4091 QVERIFY(rootObject != 0);
4092 QObject *childObject = rootObject->findChild<QObject*>("text");
4093 QVERIFY(childObject != 0);
4094 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4095 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4096 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4099 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4100 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
4101 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4103 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4104 QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
4105 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4107 QMetaObject::invokeMethod(object, "deassignCircular");
4108 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4109 QCoreApplication::processEvents();
4110 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4114 // Ensure that QObject type conversion works on binding assignment
4115 void tst_qdeclarativeecmascript::elementAssign()
4117 QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
4119 QObject *object = component.create();
4120 QVERIFY(object != 0);
4122 QCOMPARE(object->property("test").toBool(), true);
4128 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4130 QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
4132 QObject *object = component.create();
4133 QVERIFY(object != 0);
4135 QCOMPARE(object->property("test").toBool(), true);
4141 void tst_qdeclarativeecmascript::objectConversion()
4143 QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
4145 QObject *object = component.create();
4146 QVERIFY(object != 0);
4148 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4149 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4156 void tst_qdeclarativeecmascript::booleanConversion()
4158 QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
4160 QObject *object = component.create();
4161 QVERIFY(object != 0);
4163 QCOMPARE(object->property("test_true1").toBool(), true);
4164 QCOMPARE(object->property("test_true2").toBool(), true);
4165 QCOMPARE(object->property("test_true3").toBool(), true);
4166 QCOMPARE(object->property("test_true4").toBool(), true);
4167 QCOMPARE(object->property("test_true5").toBool(), true);
4169 QCOMPARE(object->property("test_false1").toBool(), false);
4170 QCOMPARE(object->property("test_false2").toBool(), false);
4171 QCOMPARE(object->property("test_false3").toBool(), false);
4176 void tst_qdeclarativeecmascript::handleReferenceManagement()
4181 // Linear QObject reference
4182 QDeclarativeEngine hrmEngine;
4183 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
4184 QObject *object = component.create();
4185 QVERIFY(object != 0);
4186 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4187 cro->setEngine(&hrmEngine);
4188 cro->setDtorCount(&dtorCount);
4189 QMetaObject::invokeMethod(object, "createReference");
4191 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4193 hrmEngine.collectGarbage();
4194 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4195 QCoreApplication::processEvents();
4196 QCOMPARE(dtorCount, 3);
4201 // Circular QObject reference
4202 QDeclarativeEngine hrmEngine;
4203 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
4204 QObject *object = component.create();
4205 QVERIFY(object != 0);
4206 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4207 cro->setEngine(&hrmEngine);
4208 cro->setDtorCount(&dtorCount);
4209 QMetaObject::invokeMethod(object, "circularReference");
4211 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4213 hrmEngine.collectGarbage();
4214 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4215 QCoreApplication::processEvents();
4216 QCOMPARE(dtorCount, 3);
4221 // Linear handle reference
4222 QDeclarativeEngine hrmEngine;
4223 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
4224 QObject *object = component.create();
4225 QVERIFY(object != 0);
4226 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4228 crh->setEngine(&hrmEngine);
4229 crh->setDtorCount(&dtorCount);
4230 QMetaObject::invokeMethod(object, "createReference");
4231 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4232 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4233 QVERIFY(first != 0);
4234 QVERIFY(second != 0);
4235 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4236 // now we have to reparent second and make second owned by JS.
4237 second->setParent(0);
4238 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4240 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4242 hrmEngine.collectGarbage();
4243 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4244 QCoreApplication::processEvents();
4245 QCOMPARE(dtorCount, 3);
4250 // Circular handle reference
4251 QDeclarativeEngine hrmEngine;
4252 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
4253 QObject *object = component.create();
4254 QVERIFY(object != 0);
4255 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4257 crh->setEngine(&hrmEngine);
4258 crh->setDtorCount(&dtorCount);
4259 QMetaObject::invokeMethod(object, "circularReference");
4260 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4261 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4262 QVERIFY(first != 0);
4263 QVERIFY(second != 0);
4264 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4265 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4266 // now we have to reparent and change ownership.
4267 first->setParent(0);
4268 second->setParent(0);
4269 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4270 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4272 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4274 hrmEngine.collectGarbage();
4275 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4276 QCoreApplication::processEvents();
4277 QCOMPARE(dtorCount, 3);
4282 // multiple engine interaction - linear reference
4283 QDeclarativeEngine hrmEngine1;
4284 QDeclarativeEngine hrmEngine2;
4285 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4286 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4287 QObject *object1 = component1.create();
4288 QObject *object2 = component2.create();
4289 QVERIFY(object1 != 0);
4290 QVERIFY(object2 != 0);
4291 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4292 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4295 crh1->setEngine(&hrmEngine1);
4296 crh2->setEngine(&hrmEngine2);
4297 crh1->setDtorCount(&dtorCount);
4298 crh2->setDtorCount(&dtorCount);
4299 QMetaObject::invokeMethod(object1, "createReference");
4300 QMetaObject::invokeMethod(object2, "createReference");
4301 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4302 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4303 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4304 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4305 QVERIFY(first1 != 0);
4306 QVERIFY(second1 != 0);
4307 QVERIFY(first2 != 0);
4308 QVERIFY(second2 != 0);
4309 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4310 // now we have to reparent second2 and make second2 owned by JS.
4311 second2->setParent(0);
4312 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4314 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4315 QCoreApplication::processEvents();
4316 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4319 hrmEngine1.collectGarbage();
4320 hrmEngine2.collectGarbage();
4321 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4322 QCoreApplication::processEvents();
4323 QCOMPARE(dtorCount, 6);
4328 // multiple engine interaction - circular reference
4329 QDeclarativeEngine hrmEngine1;
4330 QDeclarativeEngine hrmEngine2;
4331 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4332 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4333 QObject *object1 = component1.create();
4334 QObject *object2 = component2.create();
4335 QVERIFY(object1 != 0);
4336 QVERIFY(object2 != 0);
4337 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4338 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4341 crh1->setEngine(&hrmEngine1);
4342 crh2->setEngine(&hrmEngine2);
4343 crh1->setDtorCount(&dtorCount);
4344 crh2->setDtorCount(&dtorCount);
4345 QMetaObject::invokeMethod(object1, "createReference");
4346 QMetaObject::invokeMethod(object2, "createReference");
4347 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4348 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4349 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4350 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4351 QVERIFY(first1 != 0);
4352 QVERIFY(second1 != 0);
4353 QVERIFY(first2 != 0);
4354 QVERIFY(second2 != 0);
4355 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4356 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4357 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4358 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4359 // now we have to reparent and change ownership to JS.
4360 first1->setParent(0);
4361 second1->setParent(0);
4362 first2->setParent(0);
4363 second2->setParent(0);
4364 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4365 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4366 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4367 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4369 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4370 QCoreApplication::processEvents();
4371 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4374 hrmEngine1.collectGarbage();
4375 hrmEngine2.collectGarbage();
4376 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4377 QCoreApplication::processEvents();
4378 QCOMPARE(dtorCount, 6);
4383 // multiple engine interaction - linear reference with engine deletion
4384 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4385 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4386 QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4387 QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4388 QObject *object1 = component1.create();
4389 QObject *object2 = component2.create();
4390 QVERIFY(object1 != 0);
4391 QVERIFY(object2 != 0);
4392 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4393 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4396 crh1->setEngine(hrmEngine1);
4397 crh2->setEngine(hrmEngine2);
4398 crh1->setDtorCount(&dtorCount);
4399 crh2->setDtorCount(&dtorCount);
4400 QMetaObject::invokeMethod(object1, "createReference");
4401 QMetaObject::invokeMethod(object2, "createReference");
4402 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4403 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4404 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4405 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4406 QVERIFY(first1 != 0);
4407 QVERIFY(second1 != 0);
4408 QVERIFY(first2 != 0);
4409 QVERIFY(second2 != 0);
4410 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4411 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4412 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4413 // now we have to reparent and change ownership to JS.
4414 first1->setParent(crh1);
4415 second1->setParent(0);
4416 first2->setParent(0);
4417 second2->setParent(0);
4418 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4419 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4420 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4422 QCOMPARE(dtorCount, 0);
4425 QCOMPARE(dtorCount, 0);
4428 hrmEngine1->collectGarbage();
4429 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4430 QCoreApplication::processEvents();
4431 QCOMPARE(dtorCount, 6);
4436 void tst_qdeclarativeecmascript::stringArg()
4438 QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
4439 QObject *object = component.create();
4440 QVERIFY(object != 0);
4441 QMetaObject::invokeMethod(object, "success");
4442 QVERIFY(object->property("returnValue").toBool());
4444 QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4445 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4446 QMetaObject::invokeMethod(object, "failure");
4447 QVERIFY(object->property("returnValue").toBool());
4452 void tst_qdeclarativeecmascript::readonlyDeclaration()
4454 QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
4456 QObject *object = component.create();
4457 QVERIFY(object != 0);
4459 QCOMPARE(object->property("test").toBool(), true);
4464 Q_DECLARE_METATYPE(QList<int>)
4465 Q_DECLARE_METATYPE(QList<qreal>)
4466 Q_DECLARE_METATYPE(QList<bool>)
4467 Q_DECLARE_METATYPE(QList<QString>)
4468 Q_DECLARE_METATYPE(QList<QUrl>)
4469 void tst_qdeclarativeecmascript::sequenceConversionRead()
4472 QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
4473 QDeclarativeComponent component(&engine, qmlFile);
4474 QObject *object = component.create();
4475 QVERIFY(object != 0);
4476 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4479 QMetaObject::invokeMethod(object, "readSequences");
4480 QList<int> intList; intList << 1 << 2 << 3 << 4;
4481 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4482 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4483 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4484 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4485 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4486 QList<bool> boolList; boolList << true << false << true << false;
4487 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4488 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4489 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4490 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4491 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4492 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4493 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4494 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4495 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4496 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4497 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4499 QMetaObject::invokeMethod(object, "readSequenceElements");
4500 QCOMPARE(object->property("intVal").toInt(), 2);
4501 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4502 QCOMPARE(object->property("boolVal").toBool(), false);
4503 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4504 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4505 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4507 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4508 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4510 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4511 QDeclarativeProperty seqProp(seq, "intListProperty");
4512 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4513 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4514 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4516 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4517 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4523 QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
4524 QDeclarativeComponent component(&engine, qmlFile);
4525 QObject *object = component.create();
4526 QVERIFY(object != 0);
4527 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4530 // we haven't registered QList<QPoint> as a sequence type.
4531 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4532 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4533 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4534 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4536 QMetaObject::invokeMethod(object, "performTest");
4538 // QList<QPoint> has not been registered as a sequence type.
4539 QCOMPARE(object->property("pointListLength").toInt(), 0);
4540 QVERIFY(!object->property("pointList").isValid());
4541 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4542 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4543 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4549 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4552 QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
4553 QDeclarativeComponent component(&engine, qmlFile);
4554 QObject *object = component.create();
4555 QVERIFY(object != 0);
4556 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4559 QMetaObject::invokeMethod(object, "writeSequences");
4560 QCOMPARE(object->property("success").toBool(), true);
4562 QMetaObject::invokeMethod(object, "writeSequenceElements");
4563 QCOMPARE(object->property("success").toBool(), true);
4565 QMetaObject::invokeMethod(object, "writeOtherElements");
4566 QCOMPARE(object->property("success").toBool(), true);
4568 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4569 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4575 QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
4576 QDeclarativeComponent component(&engine, qmlFile);
4577 QObject *object = component.create();
4578 QVERIFY(object != 0);
4579 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4582 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4583 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4584 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4586 QMetaObject::invokeMethod(object, "performTest");
4588 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4589 QCOMPARE(seq->pointListProperty(), pointList);
4595 void tst_qdeclarativeecmascript::sequenceConversionArray()
4597 // ensure that in JS the returned sequences act just like normal JS Arrays.
4598 QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
4599 QDeclarativeComponent component(&engine, qmlFile);
4600 QObject *object = component.create();
4601 QVERIFY(object != 0);
4602 QMetaObject::invokeMethod(object, "indexedAccess");
4603 QVERIFY(object->property("success").toBool());
4604 QMetaObject::invokeMethod(object, "arrayOperations");
4605 QVERIFY(object->property("success").toBool());
4606 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4607 QVERIFY(object->property("success").toBool());
4608 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4609 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4614 void tst_qdeclarativeecmascript::sequenceConversionIndexes()
4616 // ensure that we gracefully fail if unsupported index values are specified.
4617 // Qt container classes only support non-negative, signed integer index values.
4618 QUrl qmlFile = testFileUrl("sequenceConversion.indexes.qml");
4619 QDeclarativeComponent component(&engine, qmlFile);
4620 QObject *object = component.create();
4621 QVERIFY(object != 0);
4622 QString w1 = qmlFile.toString() + QLatin1String(":34: Index out of range during length set");
4623 QString w2 = qmlFile.toString() + QLatin1String(":41: Index out of range during indexed set");
4624 QString w3 = qmlFile.toString() + QLatin1String(":48: Index out of range during indexed get");
4625 QString w4 = qmlFile.toString() + QLatin1String(":78: std::bad_alloc during length set");
4626 QString w5 = qmlFile.toString() + QLatin1String(":83: std::bad_alloc during indexed set");
4627 QTest::ignoreMessage(QtWarningMsg, qPrintable(w1));
4628 QTest::ignoreMessage(QtWarningMsg, qPrintable(w2));
4629 QTest::ignoreMessage(QtWarningMsg, qPrintable(w3));
4630 QTest::ignoreMessage(QtWarningMsg, qPrintable(w4));
4631 QTest::ignoreMessage(QtWarningMsg, qPrintable(w5));
4632 QMetaObject::invokeMethod(object, "indexedAccess");
4633 QVERIFY(object->property("success").toBool());
4637 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4639 // ensure that sequence conversion operations work correctly in a worker thread
4640 // and that serialisation between the main and worker thread succeeds.
4641 QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
4642 QDeclarativeComponent component(&engine, qmlFile);
4643 QObject *object = component.create();
4644 QVERIFY(object != 0);
4646 QMetaObject::invokeMethod(object, "testIntSequence");
4647 QTRY_VERIFY(object->property("finished").toBool());
4648 QVERIFY(object->property("success").toBool());
4650 QMetaObject::invokeMethod(object, "testQrealSequence");
4651 QTRY_VERIFY(object->property("finished").toBool());
4652 QVERIFY(object->property("success").toBool());
4654 QMetaObject::invokeMethod(object, "testBoolSequence");
4655 QTRY_VERIFY(object->property("finished").toBool());
4656 QVERIFY(object->property("success").toBool());
4658 QMetaObject::invokeMethod(object, "testStringSequence");
4659 QTRY_VERIFY(object->property("finished").toBool());
4660 QVERIFY(object->property("success").toBool());
4662 QMetaObject::invokeMethod(object, "testQStringSequence");
4663 QTRY_VERIFY(object->property("finished").toBool());
4664 QVERIFY(object->property("success").toBool());
4666 QMetaObject::invokeMethod(object, "testUrlSequence");
4667 QTRY_VERIFY(object->property("finished").toBool());
4668 QVERIFY(object->property("success").toBool());
4670 QMetaObject::invokeMethod(object, "testVariantSequence");
4671 QTRY_VERIFY(object->property("finished").toBool());
4672 QVERIFY(object->property("success").toBool());
4677 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4680 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
4681 QDeclarativeComponent component(&engine, qmlFile);
4682 QObject *object = component.create();
4683 QVERIFY(object != 0);
4684 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4685 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4686 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4687 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4688 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4693 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
4694 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4695 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4696 QDeclarativeComponent component(&engine, qmlFile);
4697 QObject *object = component.create();
4698 QVERIFY(object != 0);
4703 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4705 QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
4706 QDeclarativeComponent component(&engine, qmlFile);
4707 QObject *object = component.create();
4708 QVERIFY(object != 0);
4709 QMetaObject::invokeMethod(object, "testCopySequences");
4710 QCOMPARE(object->property("success").toBool(), true);
4711 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4712 QCOMPARE(object->property("success").toBool(), true);
4713 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4714 QCOMPARE(object->property("success").toBool(), true);
4718 void tst_qdeclarativeecmascript::assignSequenceTypes()
4720 // test binding array to sequence type property
4722 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
4723 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4724 QVERIFY(object != 0);
4725 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4726 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4727 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4728 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4729 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4730 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4734 // test binding literal to sequence type property
4736 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
4737 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4738 QVERIFY(object != 0);
4739 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4740 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4741 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4742 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4743 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4744 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4748 // test binding single value to sequence type property
4750 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
4751 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4752 QVERIFY(object != 0);
4753 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4754 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4755 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4756 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4760 // test assigning array to sequence type property in js function
4762 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
4763 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4764 QVERIFY(object != 0);
4765 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4766 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4767 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4768 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4769 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4770 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4774 // test assigning literal to sequence type property in js function
4776 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
4777 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4778 QVERIFY(object != 0);
4779 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4780 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4781 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4782 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4783 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4784 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4788 // test assigning single value to sequence type property in js function
4790 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
4791 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4792 QVERIFY(object != 0);
4793 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4794 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4795 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4796 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4800 // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
4802 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
4803 QObject *object = component.create();
4804 QVERIFY(object != 0);
4805 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
4806 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
4807 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
4808 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
4809 MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
4810 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
4811 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4812 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4813 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4814 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4815 QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4820 // Test that assigning a null object works
4821 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4822 void tst_qdeclarativeecmascript::nullObjectBinding()
4824 QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
4826 QObject *object = component.create();
4827 QVERIFY(object != 0);
4829 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4834 // Test that bindings don't evaluate once the engine has been destroyed
4835 void tst_qdeclarativeecmascript::deletedEngine()
4837 QDeclarativeEngine *engine = new QDeclarativeEngine;
4838 QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
4840 QObject *object = component.create();
4841 QVERIFY(object != 0);
4843 QCOMPARE(object->property("a").toInt(), 39);
4844 object->setProperty("b", QVariant(9));
4845 QCOMPARE(object->property("a").toInt(), 117);
4849 QCOMPARE(object->property("a").toInt(), 117);
4850 object->setProperty("b", QVariant(10));
4851 QCOMPARE(object->property("a").toInt(), 117);
4856 // Test the crashing part of QTBUG-9705
4857 void tst_qdeclarativeecmascript::libraryScriptAssert()
4859 QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
4861 QObject *object = component.create();
4862 QVERIFY(object != 0);
4867 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4869 QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
4871 QObject *object = component.create();
4872 QVERIFY(object != 0);
4874 QCOMPARE(object->property("test1").toInt(), 10);
4875 QCOMPARE(object->property("test2").toInt(), 11);
4877 object->setProperty("runTest", true);
4879 QCOMPARE(object->property("test1"), QVariant());
4880 QCOMPARE(object->property("test2"), QVariant());
4886 void tst_qdeclarativeecmascript::qtbug_9792()
4888 QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
4890 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4892 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4893 QVERIFY(object != 0);
4895 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4896 object->basicSignal();
4900 transientErrorsMsgCount = 0;
4901 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4903 object->basicSignal();
4905 qInstallMsgHandler(old);
4907 QCOMPARE(transientErrorsMsgCount, 0);
4912 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4913 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4915 QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
4917 QObject *o = component.create();
4920 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4921 QVERIFY(nested != 0);
4923 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4926 nested = qvariant_cast<QObject *>(o->property("object"));
4927 QVERIFY(nested == 0);
4929 // If the bug is present, the next line will crash
4933 // Test that we shut down without stupid warnings
4934 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4937 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
4939 QObject *o = component.create();
4941 transientErrorsMsgCount = 0;
4942 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4946 qInstallMsgHandler(old);
4948 QCOMPARE(transientErrorsMsgCount, 0);
4953 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
4955 QObject *o = component.create();
4957 transientErrorsMsgCount = 0;
4958 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4962 qInstallMsgHandler(old);
4964 QCOMPARE(transientErrorsMsgCount, 0);
4968 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4971 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
4973 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4976 QVERIFY(o->objectProperty() != 0);
4978 o->setProperty("runTest", true);
4980 QVERIFY(o->objectProperty() == 0);
4986 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
4988 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4991 QVERIFY(o->objectProperty() == 0);
4997 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4999 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
5001 QString url = component.url().toString();
5002 QString warning = url + ":4: Unable to assign a function to a property.";
5003 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5005 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5008 QVERIFY(!o->property("a").isValid());
5013 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
5015 QFETCH(QString, triggerProperty);
5017 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
5018 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
5020 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5022 QVERIFY(!o->property("a").isValid());
5024 o->setProperty("aNumber", QVariant(5));
5025 o->setProperty(triggerProperty.toUtf8().constData(), true);
5026 QCOMPARE(o->property("a"), QVariant(50));
5028 o->setProperty("aNumber", QVariant(10));
5029 QCOMPARE(o->property("a"), QVariant(100));
5034 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
5036 QTest::addColumn<QString>("triggerProperty");
5038 QTest::newRow("assign to property") << "assignToProperty";
5039 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
5041 QTest::newRow("assign to value type") << "assignToValueType";
5043 QTest::newRow("use 'this'") << "assignWithThis";
5044 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
5047 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
5049 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
5050 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
5052 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5054 QVERIFY(!o->property("a").isValid());
5056 o->setProperty("assignFuncWithoutReturn", true);
5057 QVERIFY(!o->property("a").isValid());
5059 QString url = component.url().toString();
5060 QString warning = url + ":67: Unable to assign QString to int";
5061 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5062 o->setProperty("assignWrongType", true);
5064 warning = url + ":71: Unable to assign QString to int";
5065 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5066 o->setProperty("assignWrongTypeToValueType", true);
5071 void tst_qdeclarativeecmascript::eval()
5073 QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
5075 QObject *o = component.create();
5078 QCOMPARE(o->property("test1").toBool(), true);
5079 QCOMPARE(o->property("test2").toBool(), true);
5080 QCOMPARE(o->property("test3").toBool(), true);
5081 QCOMPARE(o->property("test4").toBool(), true);
5082 QCOMPARE(o->property("test5").toBool(), true);
5087 void tst_qdeclarativeecmascript::function()
5089 QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
5091 QObject *o = component.create();
5094 QCOMPARE(o->property("test1").toBool(), true);
5095 QCOMPARE(o->property("test2").toBool(), true);
5096 QCOMPARE(o->property("test3").toBool(), true);
5101 void tst_qdeclarativeecmascript::functionException()
5103 // QTBUG-24037 - shouldn't crash.
5104 QString errstr = testFileUrl("v8functionException.qml").toString() + QLatin1String(":13: SyntaxError: Unexpected token ILLEGAL");
5105 QTest::ignoreMessage(QtWarningMsg, qPrintable(errstr));
5106 QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Exception occurred during compilation of function: dynamicSlot()");
5107 QDeclarativeComponent component(&engine, testFileUrl("v8functionException.qml"));
5108 QObject *o = component.create();
5110 QMetaObject::invokeMethod(o, "dynamicSlot");
5114 // Test the "Qt.include" method
5115 void tst_qdeclarativeecmascript::include()
5117 // Non-library relative include
5119 QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
5120 QObject *o = component.create();
5123 QCOMPARE(o->property("test0").toInt(), 99);
5124 QCOMPARE(o->property("test1").toBool(), true);
5125 QCOMPARE(o->property("test2").toBool(), true);
5126 QCOMPARE(o->property("test2_1").toBool(), true);
5127 QCOMPARE(o->property("test3").toBool(), true);
5128 QCOMPARE(o->property("test3_1").toBool(), true);
5133 // Library relative include
5135 QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
5136 QObject *o = component.create();
5139 QCOMPARE(o->property("test0").toInt(), 99);
5140 QCOMPARE(o->property("test1").toBool(), true);
5141 QCOMPARE(o->property("test2").toBool(), true);
5142 QCOMPARE(o->property("test2_1").toBool(), true);
5143 QCOMPARE(o->property("test3").toBool(), true);
5144 QCOMPARE(o->property("test3_1").toBool(), true);
5151 QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
5152 QObject *o = component.create();
5155 QCOMPARE(o->property("test1").toBool(), true);
5156 QCOMPARE(o->property("test2").toBool(), true);
5157 QCOMPARE(o->property("test3").toBool(), true);
5158 QCOMPARE(o->property("test4").toBool(), true);
5159 QCOMPARE(o->property("test5").toBool(), true);
5160 QCOMPARE(o->property("test6").toBool(), true);
5165 // Including file with ".pragma library"
5167 QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
5168 QObject *o = component.create();
5170 QCOMPARE(o->property("test1").toInt(), 100);
5177 TestHTTPServer server(8111);
5178 QVERIFY(server.isValid());
5179 server.serveDirectory(dataDirectory());
5181 QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
5182 QObject *o = component.create();
5185 QTRY_VERIFY(o->property("done").toBool() == true);
5186 QTRY_VERIFY(o->property("done2").toBool() == true);
5188 QCOMPARE(o->property("test1").toBool(), true);
5189 QCOMPARE(o->property("test2").toBool(), true);
5190 QCOMPARE(o->property("test3").toBool(), true);
5191 QCOMPARE(o->property("test4").toBool(), true);
5192 QCOMPARE(o->property("test5").toBool(), true);
5194 QCOMPARE(o->property("test6").toBool(), true);
5195 QCOMPARE(o->property("test7").toBool(), true);
5196 QCOMPARE(o->property("test8").toBool(), true);
5197 QCOMPARE(o->property("test9").toBool(), true);
5198 QCOMPARE(o->property("test10").toBool(), true);
5205 TestHTTPServer server(8111);
5206 QVERIFY(server.isValid());
5207 server.serveDirectory(dataDirectory());
5209 QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
5210 QObject *o = component.create();
5213 QTRY_VERIFY(o->property("done").toBool() == true);
5215 QCOMPARE(o->property("test1").toBool(), true);
5216 QCOMPARE(o->property("test2").toBool(), true);
5217 QCOMPARE(o->property("test3").toBool(), true);
5223 void tst_qdeclarativeecmascript::signalHandlers()
5225 QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
5226 QObject *o = component.create();
5229 QVERIFY(o->property("count").toInt() == 0);
5230 QMetaObject::invokeMethod(o, "testSignalCall");
5231 QCOMPARE(o->property("count").toInt(), 1);
5233 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5234 QCOMPARE(o->property("count").toInt(), 1);
5235 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5237 QVERIFY(o->property("funcCount").toInt() == 0);
5238 QMetaObject::invokeMethod(o, "testSignalConnection");
5239 QCOMPARE(o->property("funcCount").toInt(), 1);
5241 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5242 QCOMPARE(o->property("funcCount").toInt(), 2);
5244 QMetaObject::invokeMethod(o, "testSignalDefined");
5245 QCOMPARE(o->property("definedResult").toBool(), true);
5247 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5248 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5253 void tst_qdeclarativeecmascript::qtbug_10696()
5255 QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
5256 QObject *o = component.create();
5261 void tst_qdeclarativeecmascript::qtbug_11606()
5263 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
5264 QObject *o = component.create();
5266 QCOMPARE(o->property("test").toBool(), true);
5270 void tst_qdeclarativeecmascript::qtbug_11600()
5272 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
5273 QObject *o = component.create();
5275 QCOMPARE(o->property("test").toBool(), true);
5279 void tst_qdeclarativeecmascript::qtbug_21864()
5281 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
5282 QObject *o = component.create();
5284 QCOMPARE(o->property("test").toBool(), true);
5288 void tst_qdeclarativeecmascript::rewriteMultiLineStrings()
5291 QDeclarativeComponent component(&engine, testFileUrl("rewriteMultiLineStrings.qml"));
5292 QObject *o = component.create();
5294 QTRY_COMPARE(o->property("test").toBool(), true);
5298 void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
5301 QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
5302 QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
5303 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5304 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5305 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5306 QObject *o = component.create();
5308 QCOMPARE(o->property("test").toBool(), true);
5312 // Reading and writing non-scriptable properties should fail
5313 void tst_qdeclarativeecmascript::nonscriptable()
5315 QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
5316 QObject *o = component.create();
5318 QCOMPARE(o->property("readOk").toBool(), true);
5319 QCOMPARE(o->property("writeOk").toBool(), true);
5323 // deleteLater() should not be callable from QML
5324 void tst_qdeclarativeecmascript::deleteLater()
5326 QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
5327 QObject *o = component.create();
5329 QCOMPARE(o->property("test").toBool(), true);
5333 void tst_qdeclarativeecmascript::in()
5335 QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
5336 QObject *o = component.create();
5338 QCOMPARE(o->property("test1").toBool(), true);
5339 QCOMPARE(o->property("test2").toBool(), true);
5343 void tst_qdeclarativeecmascript::typeOf()
5345 QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
5347 // These warnings should not happen once QTBUG-21864 is fixed
5348 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5349 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5351 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5352 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5354 QObject *o = component.create();
5357 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5358 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5359 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5360 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5361 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5362 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5363 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5364 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5365 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5366 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5371 void tst_qdeclarativeecmascript::sharedAttachedObject()
5373 QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
5374 QObject *o = component.create();
5376 QCOMPARE(o->property("test1").toBool(), true);
5377 QCOMPARE(o->property("test2").toBool(), true);
5382 void tst_qdeclarativeecmascript::objectName()
5384 QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
5385 QObject *o = component.create();
5388 QCOMPARE(o->property("test1").toString(), QString("hello"));
5389 QCOMPARE(o->property("test2").toString(), QString("ell"));
5391 o->setObjectName("world");
5393 QCOMPARE(o->property("test1").toString(), QString("world"));
5394 QCOMPARE(o->property("test2").toString(), QString("orl"));
5399 void tst_qdeclarativeecmascript::writeRemovesBinding()
5401 QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
5402 QObject *o = component.create();
5405 QCOMPARE(o->property("test").toBool(), true);
5410 // Test bindings assigned to alias properties actually assign to the alias' target
5411 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5413 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
5414 QObject *o = component.create();
5417 QCOMPARE(o->property("test").toBool(), true);
5422 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5423 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5426 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
5427 QObject *o = component.create();
5430 QCOMPARE(o->property("test").toBool(), true);
5436 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
5437 QObject *o = component.create();
5440 QCOMPARE(o->property("test").toBool(), true);
5446 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
5447 QObject *o = component.create();
5450 QCOMPARE(o->property("test").toBool(), true);
5456 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5457 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5460 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
5461 QObject *o = component.create();
5464 QCOMPARE(o->property("test").toBool(), true);
5470 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
5471 QObject *o = component.create();
5474 QCOMPARE(o->property("test").toBool(), true);
5480 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
5481 QObject *o = component.create();
5484 QCOMPARE(o->property("test").toBool(), true);
5490 // Allow an alais to a composite element
5492 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5494 QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
5496 QObject *object = component.create();
5497 QVERIFY(object != 0);
5502 void tst_qdeclarativeecmascript::qtbug_20344()
5504 QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
5506 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5507 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5509 QObject *object = component.create();
5510 QVERIFY(object != 0);
5515 void tst_qdeclarativeecmascript::revisionErrors()
5518 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
5519 QString url = component.url().toString();
5521 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5522 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5523 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5525 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5526 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5527 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5528 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5529 QVERIFY(object != 0);
5533 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
5534 QString url = component.url().toString();
5536 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5537 // method2, prop2 from MyRevisionedClass not available
5538 // method4, prop4 from MyRevisionedSubclass not available
5539 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5540 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5541 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5542 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5543 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5545 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5546 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5547 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5548 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5549 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5550 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5551 QVERIFY(object != 0);
5555 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
5556 QString url = component.url().toString();
5558 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5559 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5560 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5561 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5562 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5563 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5564 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5565 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5566 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5567 QVERIFY(object != 0);
5572 void tst_qdeclarativeecmascript::revision()
5575 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
5576 QString url = component.url().toString();
5578 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5579 QVERIFY(object != 0);
5583 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
5584 QString url = component.url().toString();
5586 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5587 QVERIFY(object != 0);
5591 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
5592 QString url = component.url().toString();
5594 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5595 QVERIFY(object != 0);
5598 // Test that non-root classes can resolve revisioned methods
5600 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
5602 QObject *object = component.create();
5603 QVERIFY(object != 0);
5604 QCOMPARE(object->property("test").toReal(), 11.);
5609 void tst_qdeclarativeecmascript::realToInt()
5611 QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
5612 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5613 QVERIFY(object != 0);
5615 QMetaObject::invokeMethod(object, "test1");
5616 QCOMPARE(object->value(), int(4));
5617 QMetaObject::invokeMethod(object, "test2");
5618 QCOMPARE(object->value(), int(8));
5621 void tst_qdeclarativeecmascript::urlProperty()
5624 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
5625 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5626 QVERIFY(object != 0);
5627 object->setStringProperty("http://qt-project.org");
5628 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5629 QCOMPARE(object->intProperty(), 123);
5630 QCOMPARE(object->value(), 1);
5631 QCOMPARE(object->property("result").toBool(), true);
5635 void tst_qdeclarativeecmascript::urlPropertyWithEncoding()
5638 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.2.qml"));
5639 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5640 QVERIFY(object != 0);
5641 object->setStringProperty("http://qt-project.org");
5643 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5644 QCOMPARE(object->urlProperty(), encoded);
5645 QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
5646 QCOMPARE(object->property("result").toBool(), true);
5650 void tst_qdeclarativeecmascript::urlListPropertyWithEncoding()
5653 QDeclarativeComponent component(&engine, testFileUrl("urlListProperty.qml"));
5654 QObject *object = component.create();
5655 QVERIFY(object != 0);
5656 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
5657 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
5658 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
5659 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
5660 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
5662 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5663 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
5664 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
5665 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5666 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5671 void tst_qdeclarativeecmascript::dynamicString()
5673 QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
5674 QObject *object = component.create();
5675 QVERIFY(object != 0);
5676 QCOMPARE(object->property("stringProperty").toString(),
5677 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5680 void tst_qdeclarativeecmascript::automaticSemicolon()
5682 QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
5683 QObject *object = component.create();
5684 QVERIFY(object != 0);
5687 void tst_qdeclarativeecmascript::unaryExpression()
5689 QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
5690 QObject *object = component.create();
5691 QVERIFY(object != 0);
5694 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5695 void tst_qdeclarativeecmascript::doubleEvaluate()
5697 QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
5698 QObject *object = component.create();
5699 QVERIFY(object != 0);
5700 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5702 QCOMPARE(wc->count(), 1);
5704 wc->setProperty("x", 9);
5706 QCOMPARE(wc->count(), 2);
5711 static QStringList messages;
5712 static void captureMsgHandler(QtMsgType, const char *msg)
5714 messages.append(QLatin1String(msg));
5717 void tst_qdeclarativeecmascript::nonNotifyable()
5719 QV4Compiler::enableV4(false);
5720 QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
5721 QV4Compiler::enableV4(true);
5723 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5725 QObject *object = component.create();
5726 qInstallMsgHandler(old);
5728 QVERIFY(object != 0);
5730 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5731 component.url().toString() +
5732 QLatin1String(":5 depends on non-NOTIFYable properties:");
5733 QString expected2 = QLatin1String(" ") +
5734 QLatin1String(object->metaObject()->className()) +
5735 QLatin1String("::value");
5737 QCOMPARE(messages.length(), 2);
5738 QCOMPARE(messages.at(0), expected1);
5739 QCOMPARE(messages.at(1), expected2);
5744 void tst_qdeclarativeecmascript::forInLoop()
5746 QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
5747 QObject *object = component.create();
5748 QVERIFY(object != 0);
5750 QMetaObject::invokeMethod(object, "listProperty");
5752 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5753 QCOMPARE(r.size(), 3);
5754 QCOMPARE(r[0],QLatin1String("0=obj1"));
5755 QCOMPARE(r[1],QLatin1String("1=obj2"));
5756 QCOMPARE(r[2],QLatin1String("2=obj3"));
5758 //TODO: should test for in loop for other objects (such as QObjects) as well.
5763 // An object the binding depends on is deleted while the binding is still running
5764 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5766 QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
5767 QObject *object = component.create();
5768 QVERIFY(object != 0);
5772 void tst_qdeclarativeecmascript::qtbug_22679()
5775 object.setStringProperty(QLatin1String("Please work correctly"));
5776 engine.rootContext()->setContextProperty("contextProp", &object);
5778 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
5779 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5780 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5782 QObject *o = component.create();
5784 QCOMPARE(warningsSpy.count(), 0);
5788 void tst_qdeclarativeecmascript::qtbug_22843_data()
5790 QTest::addColumn<bool>("library");
5792 QTest::newRow("without .pragma library") << false;
5793 QTest::newRow("with .pragma library") << true;
5796 void tst_qdeclarativeecmascript::qtbug_22843()
5798 QFETCH(bool, library);
5800 QString fileName("qtbug_22843");
5802 fileName += QLatin1String(".library");
5803 fileName += QLatin1String(".qml");
5805 QDeclarativeComponent component(&engine, testFileUrl(fileName));
5806 QString url = component.url().toString();
5807 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5808 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5810 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5811 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5812 for (int x = 0; x < 3; ++x) {
5813 warningsSpy.clear();
5814 // For libraries, only the first import attempt should produce a
5815 // SyntaxError warning; subsequent component creation should not
5816 // attempt to reload the script.
5817 bool expectSyntaxError = !library || (x == 0);
5818 if (expectSyntaxError)
5819 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5820 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5821 QObject *object = component.create();
5822 QVERIFY(object != 0);
5823 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5829 void tst_qdeclarativeecmascript::switchStatement()
5832 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
5833 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5834 QVERIFY(object != 0);
5836 // `object->value()' is the number of executed statements
5838 object->setStringProperty("A");
5839 QCOMPARE(object->value(), 5);
5841 object->setStringProperty("S");
5842 QCOMPARE(object->value(), 3);
5844 object->setStringProperty("D");
5845 QCOMPARE(object->value(), 3);
5847 object->setStringProperty("F");
5848 QCOMPARE(object->value(), 4);
5850 object->setStringProperty("something else");
5851 QCOMPARE(object->value(), 1);
5855 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
5856 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5857 QVERIFY(object != 0);
5859 // `object->value()' is the number of executed statements
5861 object->setStringProperty("A");
5862 QCOMPARE(object->value(), 5);
5864 object->setStringProperty("S");
5865 QCOMPARE(object->value(), 3);
5867 object->setStringProperty("D");
5868 QCOMPARE(object->value(), 3);
5870 object->setStringProperty("F");
5871 QCOMPARE(object->value(), 3);
5873 object->setStringProperty("something else");
5874 QCOMPARE(object->value(), 4);
5878 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
5879 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5880 QVERIFY(object != 0);
5882 // `object->value()' is the number of executed statements
5884 object->setStringProperty("A");
5885 QCOMPARE(object->value(), 5);
5887 object->setStringProperty("S");
5888 QCOMPARE(object->value(), 3);
5890 object->setStringProperty("D");
5891 QCOMPARE(object->value(), 3);
5893 object->setStringProperty("F");
5894 QCOMPARE(object->value(), 3);
5896 object->setStringProperty("something else");
5897 QCOMPARE(object->value(), 6);
5901 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
5903 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5904 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5906 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5907 QVERIFY(object != 0);
5909 // `object->value()' is the number of executed statements
5911 object->setStringProperty("A");
5912 QCOMPARE(object->value(), 5);
5914 object->setStringProperty("S");
5915 QCOMPARE(object->value(), 3);
5917 object->setStringProperty("D");
5918 QCOMPARE(object->value(), 3);
5920 object->setStringProperty("F");
5921 QCOMPARE(object->value(), 3);
5923 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5925 object->setStringProperty("something else");
5929 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
5930 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5931 QVERIFY(object != 0);
5933 // `object->value()' is the number of executed statements
5935 object->setStringProperty("A");
5936 QCOMPARE(object->value(), 1);
5938 object->setStringProperty("S");
5939 QCOMPARE(object->value(), 1);
5941 object->setStringProperty("D");
5942 QCOMPARE(object->value(), 1);
5944 object->setStringProperty("F");
5945 QCOMPARE(object->value(), 1);
5947 object->setStringProperty("something else");
5948 QCOMPARE(object->value(), 1);
5952 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
5953 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5954 QVERIFY(object != 0);
5956 // `object->value()' is the number of executed statements
5958 object->setStringProperty("A");
5959 QCOMPARE(object->value(), 123);
5961 object->setStringProperty("S");
5962 QCOMPARE(object->value(), 123);
5964 object->setStringProperty("D");
5965 QCOMPARE(object->value(), 321);
5967 object->setStringProperty("F");
5968 QCOMPARE(object->value(), 321);
5970 object->setStringProperty("something else");
5971 QCOMPARE(object->value(), 0);
5975 void tst_qdeclarativeecmascript::withStatement()
5978 QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
5979 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5980 QVERIFY(object != 0);
5982 QCOMPARE(object->value(), 123);
5986 void tst_qdeclarativeecmascript::tryStatement()
5989 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
5990 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5991 QVERIFY(object != 0);
5993 QCOMPARE(object->value(), 123);
5997 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
5998 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5999 QVERIFY(object != 0);
6001 QCOMPARE(object->value(), 321);
6005 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
6006 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
6007 QVERIFY(object != 0);
6009 QCOMPARE(object->value(), 1);
6013 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
6014 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
6015 QVERIFY(object != 0);
6017 QCOMPARE(object->value(), 1);
6021 class CppInvokableWithQObjectDerived : public QObject
6025 CppInvokableWithQObjectDerived() {}
6026 ~CppInvokableWithQObjectDerived() {}
6028 Q_INVOKABLE MyQmlObject *createMyQmlObject(QString data)
6030 MyQmlObject *obj = new MyQmlObject();
6031 obj->setStringProperty(data);
6035 Q_INVOKABLE QString getStringProperty(MyQmlObject *obj)
6037 return obj->stringProperty();
6041 void tst_qdeclarativeecmascript::invokableWithQObjectDerived()
6043 CppInvokableWithQObjectDerived invokable;
6046 QDeclarativeEngine engine;
6047 engine.rootContext()->setContextProperty("invokable", &invokable);
6049 QDeclarativeComponent component(&engine, testFileUrl("qobjectDerivedArgument.qml"));
6051 QObject *object = component.create();
6053 QVERIFY(object != 0);
6054 QVERIFY(object->property("result").value<bool>() == true);
6060 QTEST_MAIN(tst_qdeclarativeecmascript)
6062 #include "tst_qdeclarativeecmascript.moc"