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 QObject *object = component.create();
1574 QVERIFY(object != 0);
1578 static int transientErrorsMsgCount = 0;
1579 static void transientErrorsMsgHandler(QtMsgType, const char *)
1581 ++transientErrorsMsgCount;
1584 // Check that transient binding errors are not displayed
1585 void tst_qdeclarativeecmascript::transientErrors()
1588 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
1590 transientErrorsMsgCount = 0;
1591 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1593 QObject *object = component.create();
1594 QVERIFY(object != 0);
1596 qInstallMsgHandler(old);
1598 QCOMPARE(transientErrorsMsgCount, 0);
1603 // One binding erroring multiple times, but then resolving
1605 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
1607 transientErrorsMsgCount = 0;
1608 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1610 QObject *object = component.create();
1611 QVERIFY(object != 0);
1613 qInstallMsgHandler(old);
1615 QCOMPARE(transientErrorsMsgCount, 0);
1621 // Check that errors during shutdown are minimized
1622 void tst_qdeclarativeecmascript::shutdownErrors()
1624 QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
1625 QObject *object = component.create();
1626 QVERIFY(object != 0);
1628 transientErrorsMsgCount = 0;
1629 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1633 qInstallMsgHandler(old);
1634 QCOMPARE(transientErrorsMsgCount, 0);
1637 void tst_qdeclarativeecmascript::compositePropertyType()
1639 QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
1641 QTest::ignoreMessage(QtDebugMsg, "hello world");
1642 QObject *object = qobject_cast<QObject *>(component.create());
1647 void tst_qdeclarativeecmascript::jsObject()
1649 QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
1650 QObject *object = component.create();
1651 QVERIFY(object != 0);
1653 QCOMPARE(object->property("test").toInt(), 92);
1658 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1661 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
1662 QObject *object = component.create();
1663 QVERIFY(object != 0);
1665 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1667 object->setProperty("setUndefined", true);
1669 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1671 object->setProperty("setUndefined", false);
1673 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1678 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
1679 QObject *object = component.create();
1680 QVERIFY(object != 0);
1682 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1684 QMetaObject::invokeMethod(object, "doReset");
1686 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1692 // Aliases to variant properties should work
1693 void tst_qdeclarativeecmascript::qtbug_22464()
1695 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
1696 QObject *object = component.create();
1697 QVERIFY(object != 0);
1699 QCOMPARE(object->property("test").toBool(), true);
1704 void tst_qdeclarativeecmascript::qtbug_21580()
1706 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
1708 QObject *object = component.create();
1709 QVERIFY(object != 0);
1711 QCOMPARE(object->property("test").toBool(), true);
1717 void tst_qdeclarativeecmascript::bug1()
1719 QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
1720 QObject *object = component.create();
1721 QVERIFY(object != 0);
1723 QCOMPARE(object->property("test").toInt(), 14);
1725 object->setProperty("a", 11);
1727 QCOMPARE(object->property("test").toInt(), 3);
1729 object->setProperty("b", true);
1731 QCOMPARE(object->property("test").toInt(), 9);
1736 void tst_qdeclarativeecmascript::bug2()
1738 QDeclarativeComponent component(&engine);
1739 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1741 QObject *object = component.create();
1742 QVERIFY(object != 0);
1747 // Don't crash in createObject when the component has errors.
1748 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1750 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1751 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1752 QVERIFY(object != 0);
1754 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1755 QMetaObject::invokeMethod(object, "dontCrash");
1756 QObject *created = object->objectProperty();
1757 QVERIFY(created == 0);
1762 // ownership transferred to JS, ensure that GC runs the dtor
1763 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1766 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1768 // allow the engine to go out of scope too.
1770 QDeclarativeEngine dcoEngine;
1771 QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
1772 QObject *object = component.create();
1773 QVERIFY(object != 0);
1774 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1775 QVERIFY(mdcdo != 0);
1776 mdcdo->setDtorCount(&dtorCount);
1778 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1779 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1781 // we do this once manually, but it should be done automatically
1782 // when the engine goes out of scope (since it should gc in dtor)
1783 QMetaObject::invokeMethod(object, "performGc");
1786 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1787 QCoreApplication::processEvents();
1793 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
1794 QCoreApplication::processEvents();
1795 QCOMPARE(dtorCount, expectedDtorCount);
1798 void tst_qdeclarativeecmascript::regExpBug()
1802 QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
1803 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1804 QVERIFY(object != 0);
1805 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1811 QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
1812 QDeclarativeComponent component(&engine, testFileUrl("regExp.2.qml"));
1813 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1814 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1816 QCOMPARE(component.errorString(), err);
1820 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1822 QString functionSource = QLatin1String("(function(object) { return ") +
1823 QLatin1String(source) + QLatin1String(" })");
1825 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1828 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1829 if (function.IsEmpty())
1831 v8::Handle<v8::Value> args[] = { o };
1832 function->Call(engine->global(), 1, args);
1833 return tc.HasCaught();
1836 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1837 const char *source, v8::Handle<v8::Value> result)
1839 QString functionSource = QLatin1String("(function(object) { return ") +
1840 QLatin1String(source) + QLatin1String(" })");
1842 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1845 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1846 if (function.IsEmpty())
1848 v8::Handle<v8::Value> args[] = { o };
1850 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1855 return value->StrictEquals(result);
1858 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1861 QString functionSource = QLatin1String("(function(object) { return ") +
1862 QLatin1String(source) + QLatin1String(" })");
1864 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1866 return v8::Handle<v8::Value>();
1867 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1868 if (function.IsEmpty())
1869 return v8::Handle<v8::Value>();
1870 v8::Handle<v8::Value> args[] = { o };
1872 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1875 return v8::Handle<v8::Value>();
1879 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1880 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1881 #define EVALUATE(source) evaluate(engine, object, source)
1883 void tst_qdeclarativeecmascript::callQtInvokables()
1885 MyInvokableObject o;
1887 QDeclarativeEngine qmlengine;
1888 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1890 QV8Engine *engine = ep->v8engine();
1892 v8::HandleScope handle_scope;
1893 v8::Context::Scope scope(engine->context());
1895 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1897 // Non-existent methods
1899 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1900 QCOMPARE(o.error(), false);
1901 QCOMPARE(o.invoked(), -1);
1902 QCOMPARE(o.actuals().count(), 0);
1905 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1906 QCOMPARE(o.error(), false);
1907 QCOMPARE(o.invoked(), -1);
1908 QCOMPARE(o.actuals().count(), 0);
1910 // Insufficient arguments
1912 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1913 QCOMPARE(o.error(), false);
1914 QCOMPARE(o.invoked(), -1);
1915 QCOMPARE(o.actuals().count(), 0);
1918 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1919 QCOMPARE(o.error(), false);
1920 QCOMPARE(o.invoked(), -1);
1921 QCOMPARE(o.actuals().count(), 0);
1923 // Excessive arguments
1925 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1926 QCOMPARE(o.error(), false);
1927 QCOMPARE(o.invoked(), 8);
1928 QCOMPARE(o.actuals().count(), 1);
1929 QCOMPARE(o.actuals().at(0), QVariant(10));
1932 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1933 QCOMPARE(o.error(), false);
1934 QCOMPARE(o.invoked(), 9);
1935 QCOMPARE(o.actuals().count(), 2);
1936 QCOMPARE(o.actuals().at(0), QVariant(10));
1937 QCOMPARE(o.actuals().at(1), QVariant(11));
1939 // Test return types
1941 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1942 QCOMPARE(o.error(), false);
1943 QCOMPARE(o.invoked(), 0);
1944 QCOMPARE(o.actuals().count(), 0);
1947 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1948 QCOMPARE(o.error(), false);
1949 QCOMPARE(o.invoked(), 1);
1950 QCOMPARE(o.actuals().count(), 0);
1953 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1954 QCOMPARE(o.error(), false);
1955 QCOMPARE(o.invoked(), 2);
1956 QCOMPARE(o.actuals().count(), 0);
1960 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1961 QVERIFY(!ret.IsEmpty());
1962 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1963 QCOMPARE(o.error(), false);
1964 QCOMPARE(o.invoked(), 3);
1965 QCOMPARE(o.actuals().count(), 0);
1970 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1971 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1972 QCOMPARE(o.error(), false);
1973 QCOMPARE(o.invoked(), 4);
1974 QCOMPARE(o.actuals().count(), 0);
1978 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1979 QCOMPARE(o.error(), false);
1980 QCOMPARE(o.invoked(), 5);
1981 QCOMPARE(o.actuals().count(), 0);
1985 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1986 QVERIFY(ret->IsString());
1987 QCOMPARE(engine->toString(ret), QString("Hello world"));
1988 QCOMPARE(o.error(), false);
1989 QCOMPARE(o.invoked(), 6);
1990 QCOMPARE(o.actuals().count(), 0);
1994 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1995 QCOMPARE(o.error(), false);
1996 QCOMPARE(o.invoked(), 7);
1997 QCOMPARE(o.actuals().count(), 0);
2001 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
2002 QCOMPARE(o.error(), false);
2003 QCOMPARE(o.invoked(), 8);
2004 QCOMPARE(o.actuals().count(), 1);
2005 QCOMPARE(o.actuals().at(0), QVariant(94));
2008 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
2009 QCOMPARE(o.error(), false);
2010 QCOMPARE(o.invoked(), 8);
2011 QCOMPARE(o.actuals().count(), 1);
2012 QCOMPARE(o.actuals().at(0), QVariant(94));
2015 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
2016 QCOMPARE(o.error(), false);
2017 QCOMPARE(o.invoked(), 8);
2018 QCOMPARE(o.actuals().count(), 1);
2019 QCOMPARE(o.actuals().at(0), QVariant(0));
2022 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
2023 QCOMPARE(o.error(), false);
2024 QCOMPARE(o.invoked(), 8);
2025 QCOMPARE(o.actuals().count(), 1);
2026 QCOMPARE(o.actuals().at(0), QVariant(0));
2029 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
2030 QCOMPARE(o.error(), false);
2031 QCOMPARE(o.invoked(), 8);
2032 QCOMPARE(o.actuals().count(), 1);
2033 QCOMPARE(o.actuals().at(0), QVariant(0));
2036 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2037 QCOMPARE(o.error(), false);
2038 QCOMPARE(o.invoked(), 8);
2039 QCOMPARE(o.actuals().count(), 1);
2040 QCOMPARE(o.actuals().at(0), QVariant(0));
2043 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2044 QCOMPARE(o.error(), false);
2045 QCOMPARE(o.invoked(), 9);
2046 QCOMPARE(o.actuals().count(), 2);
2047 QCOMPARE(o.actuals().at(0), QVariant(122));
2048 QCOMPARE(o.actuals().at(1), QVariant(9));
2051 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2052 QCOMPARE(o.error(), false);
2053 QCOMPARE(o.invoked(), 10);
2054 QCOMPARE(o.actuals().count(), 1);
2055 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2058 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2059 QCOMPARE(o.error(), false);
2060 QCOMPARE(o.invoked(), 10);
2061 QCOMPARE(o.actuals().count(), 1);
2062 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2065 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2066 QCOMPARE(o.error(), false);
2067 QCOMPARE(o.invoked(), 10);
2068 QCOMPARE(o.actuals().count(), 1);
2069 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2072 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2073 QCOMPARE(o.error(), false);
2074 QCOMPARE(o.invoked(), 10);
2075 QCOMPARE(o.actuals().count(), 1);
2076 QCOMPARE(o.actuals().at(0), QVariant(0));
2079 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2080 QCOMPARE(o.error(), false);
2081 QCOMPARE(o.invoked(), 10);
2082 QCOMPARE(o.actuals().count(), 1);
2083 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2086 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2087 QCOMPARE(o.error(), false);
2088 QCOMPARE(o.invoked(), 10);
2089 QCOMPARE(o.actuals().count(), 1);
2090 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2093 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2094 QCOMPARE(o.error(), false);
2095 QCOMPARE(o.invoked(), 11);
2096 QCOMPARE(o.actuals().count(), 1);
2097 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2100 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2101 QCOMPARE(o.error(), false);
2102 QCOMPARE(o.invoked(), 11);
2103 QCOMPARE(o.actuals().count(), 1);
2104 QCOMPARE(o.actuals().at(0), QVariant("19"));
2108 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2109 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2110 QCOMPARE(o.error(), false);
2111 QCOMPARE(o.invoked(), 11);
2112 QCOMPARE(o.actuals().count(), 1);
2113 QCOMPARE(o.actuals().at(0), QVariant(expected));
2117 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2118 QCOMPARE(o.error(), false);
2119 QCOMPARE(o.invoked(), 11);
2120 QCOMPARE(o.actuals().count(), 1);
2121 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2124 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2125 QCOMPARE(o.error(), false);
2126 QCOMPARE(o.invoked(), 11);
2127 QCOMPARE(o.actuals().count(), 1);
2128 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2131 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2132 QCOMPARE(o.error(), false);
2133 QCOMPARE(o.invoked(), 12);
2134 QCOMPARE(o.actuals().count(), 1);
2135 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2138 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2139 QCOMPARE(o.error(), false);
2140 QCOMPARE(o.invoked(), 12);
2141 QCOMPARE(o.actuals().count(), 1);
2142 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2145 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2146 QCOMPARE(o.error(), false);
2147 QCOMPARE(o.invoked(), 12);
2148 QCOMPARE(o.actuals().count(), 1);
2149 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2152 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2153 QCOMPARE(o.error(), false);
2154 QCOMPARE(o.invoked(), 12);
2155 QCOMPARE(o.actuals().count(), 1);
2156 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2159 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2160 QCOMPARE(o.error(), false);
2161 QCOMPARE(o.invoked(), 12);
2162 QCOMPARE(o.actuals().count(), 1);
2163 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2166 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2167 QCOMPARE(o.error(), false);
2168 QCOMPARE(o.invoked(), 12);
2169 QCOMPARE(o.actuals().count(), 1);
2170 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2173 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2174 QCOMPARE(o.error(), false);
2175 QCOMPARE(o.invoked(), 13);
2176 QCOMPARE(o.actuals().count(), 1);
2177 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2180 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2181 QCOMPARE(o.error(), false);
2182 QCOMPARE(o.invoked(), 13);
2183 QCOMPARE(o.actuals().count(), 1);
2184 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2187 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2188 QCOMPARE(o.error(), false);
2189 QCOMPARE(o.invoked(), 13);
2190 QCOMPARE(o.actuals().count(), 1);
2191 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2194 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2195 QCOMPARE(o.error(), false);
2196 QCOMPARE(o.invoked(), 13);
2197 QCOMPARE(o.actuals().count(), 1);
2198 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2201 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2202 QCOMPARE(o.error(), false);
2203 QCOMPARE(o.invoked(), 13);
2204 QCOMPARE(o.actuals().count(), 1);
2205 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2208 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2209 QCOMPARE(o.error(), false);
2210 QCOMPARE(o.invoked(), 14);
2211 QCOMPARE(o.actuals().count(), 1);
2212 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2215 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2216 QCOMPARE(o.error(), false);
2217 QCOMPARE(o.invoked(), 14);
2218 QCOMPARE(o.actuals().count(), 1);
2219 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2222 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2223 QCOMPARE(o.error(), false);
2224 QCOMPARE(o.invoked(), 14);
2225 QCOMPARE(o.actuals().count(), 1);
2226 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2229 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2230 QCOMPARE(o.error(), false);
2231 QCOMPARE(o.invoked(), 14);
2232 QCOMPARE(o.actuals().count(), 1);
2233 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2236 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2237 QCOMPARE(o.error(), false);
2238 QCOMPARE(o.invoked(), 15);
2239 QCOMPARE(o.actuals().count(), 2);
2240 QCOMPARE(o.actuals().at(0), QVariant(4));
2241 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2244 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2245 QCOMPARE(o.error(), false);
2246 QCOMPARE(o.invoked(), 15);
2247 QCOMPARE(o.actuals().count(), 2);
2248 QCOMPARE(o.actuals().at(0), QVariant(8));
2249 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2252 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2253 QCOMPARE(o.error(), false);
2254 QCOMPARE(o.invoked(), 15);
2255 QCOMPARE(o.actuals().count(), 2);
2256 QCOMPARE(o.actuals().at(0), QVariant(3));
2257 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2260 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2261 QCOMPARE(o.error(), false);
2262 QCOMPARE(o.invoked(), 15);
2263 QCOMPARE(o.actuals().count(), 2);
2264 QCOMPARE(o.actuals().at(0), QVariant(44));
2265 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2268 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2269 QCOMPARE(o.error(), false);
2270 QCOMPARE(o.invoked(), -1);
2271 QCOMPARE(o.actuals().count(), 0);
2274 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2275 QCOMPARE(o.error(), false);
2276 QCOMPARE(o.invoked(), 16);
2277 QCOMPARE(o.actuals().count(), 1);
2278 QCOMPARE(o.actuals().at(0), QVariant(10));
2281 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2282 QCOMPARE(o.error(), false);
2283 QCOMPARE(o.invoked(), 17);
2284 QCOMPARE(o.actuals().count(), 2);
2285 QCOMPARE(o.actuals().at(0), QVariant(10));
2286 QCOMPARE(o.actuals().at(1), QVariant(11));
2289 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2290 QCOMPARE(o.error(), false);
2291 QCOMPARE(o.invoked(), 18);
2292 QCOMPARE(o.actuals().count(), 1);
2293 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2296 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2297 QCOMPARE(o.error(), false);
2298 QCOMPARE(o.invoked(), 19);
2299 QCOMPARE(o.actuals().count(), 1);
2300 QCOMPARE(o.actuals().at(0), QVariant(9));
2303 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2304 QCOMPARE(o.error(), false);
2305 QCOMPARE(o.invoked(), 20);
2306 QCOMPARE(o.actuals().count(), 2);
2307 QCOMPARE(o.actuals().at(0), QVariant(10));
2308 QCOMPARE(o.actuals().at(1), QVariant(19));
2311 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2312 QCOMPARE(o.error(), false);
2313 QCOMPARE(o.invoked(), 20);
2314 QCOMPARE(o.actuals().count(), 2);
2315 QCOMPARE(o.actuals().at(0), QVariant(10));
2316 QCOMPARE(o.actuals().at(1), QVariant(13));
2319 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2320 QCOMPARE(o.error(), false);
2321 QCOMPARE(o.invoked(), -3);
2322 QCOMPARE(o.actuals().count(), 1);
2323 QCOMPARE(o.actuals().at(0), QVariant(9));
2326 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2327 QCOMPARE(o.error(), false);
2328 QCOMPARE(o.invoked(), 21);
2329 QCOMPARE(o.actuals().count(), 2);
2330 QCOMPARE(o.actuals().at(0), QVariant(9));
2331 QCOMPARE(o.actuals().at(1), QVariant());
2334 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2335 QCOMPARE(o.error(), false);
2336 QCOMPARE(o.invoked(), 21);
2337 QCOMPARE(o.actuals().count(), 2);
2338 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2339 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2342 // QTBUG-13047 (check that you can pass registered object types as args)
2343 void tst_qdeclarativeecmascript::invokableObjectArg()
2345 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
2347 QObject *o = component.create();
2349 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2351 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2356 // QTBUG-13047 (check that you can return registered object types from methods)
2357 void tst_qdeclarativeecmascript::invokableObjectRet()
2359 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
2361 QObject *o = component.create();
2363 QCOMPARE(o->property("test").toBool(), true);
2368 void tst_qdeclarativeecmascript::listToVariant()
2370 QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
2372 MyQmlContainer container;
2374 QDeclarativeContext context(engine.rootContext());
2375 context.setContextObject(&container);
2377 QObject *object = component.create(&context);
2378 QVERIFY(object != 0);
2380 QVariant v = object->property("test");
2381 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2382 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2388 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2389 void tst_qdeclarativeecmascript::listAssignment()
2391 QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
2392 QObject *obj = component.create();
2393 QCOMPARE(obj->property("list1length").toInt(), 2);
2394 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2395 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2396 QCOMPARE(list1.count(&list1), list2.count(&list2));
2397 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2398 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2403 void tst_qdeclarativeecmascript::multiEngineObject()
2406 obj.setStringProperty("Howdy planet");
2408 QDeclarativeEngine e1;
2409 e1.rootContext()->setContextProperty("thing", &obj);
2410 QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
2412 QDeclarativeEngine e2;
2413 e2.rootContext()->setContextProperty("thing", &obj);
2414 QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
2416 QObject *o1 = c1.create();
2417 QObject *o2 = c2.create();
2419 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2420 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2426 // Test that references to QObjects are cleanup when the object is destroyed
2427 void tst_qdeclarativeecmascript::deletedObject()
2429 QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
2431 QObject *object = component.create();
2433 QCOMPARE(object->property("test1").toBool(), true);
2434 QCOMPARE(object->property("test2").toBool(), true);
2435 QCOMPARE(object->property("test3").toBool(), true);
2436 QCOMPARE(object->property("test4").toBool(), true);
2441 void tst_qdeclarativeecmascript::attachedPropertyScope()
2443 QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
2445 QObject *object = component.create();
2446 QVERIFY(object != 0);
2448 MyQmlAttachedObject *attached =
2449 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2450 QVERIFY(attached != 0);
2452 QCOMPARE(object->property("value2").toInt(), 0);
2454 attached->emitMySignal();
2456 QCOMPARE(object->property("value2").toInt(), 9);
2461 void tst_qdeclarativeecmascript::scriptConnect()
2464 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
2466 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2467 QVERIFY(object != 0);
2469 QCOMPARE(object->property("test").toBool(), false);
2470 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2471 QCOMPARE(object->property("test").toBool(), true);
2477 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
2479 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2480 QVERIFY(object != 0);
2482 QCOMPARE(object->property("test").toBool(), false);
2483 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2484 QCOMPARE(object->property("test").toBool(), true);
2490 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
2492 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2493 QVERIFY(object != 0);
2495 QCOMPARE(object->property("test").toBool(), false);
2496 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2497 QCOMPARE(object->property("test").toBool(), true);
2503 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
2505 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2506 QVERIFY(object != 0);
2508 QCOMPARE(object->methodCalled(), false);
2509 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2510 QCOMPARE(object->methodCalled(), true);
2516 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
2518 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2519 QVERIFY(object != 0);
2521 QCOMPARE(object->methodCalled(), false);
2522 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2523 QCOMPARE(object->methodCalled(), true);
2529 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
2531 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2532 QVERIFY(object != 0);
2534 QCOMPARE(object->property("test").toInt(), 0);
2535 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2536 QCOMPARE(object->property("test").toInt(), 2);
2542 void tst_qdeclarativeecmascript::scriptDisconnect()
2545 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
2547 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2548 QVERIFY(object != 0);
2550 QCOMPARE(object->property("test").toInt(), 0);
2551 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2552 QCOMPARE(object->property("test").toInt(), 1);
2553 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2554 QCOMPARE(object->property("test").toInt(), 2);
2555 emit object->basicSignal();
2556 QCOMPARE(object->property("test").toInt(), 2);
2557 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2558 QCOMPARE(object->property("test").toInt(), 2);
2564 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
2566 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2567 QVERIFY(object != 0);
2569 QCOMPARE(object->property("test").toInt(), 0);
2570 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2571 QCOMPARE(object->property("test").toInt(), 1);
2572 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2573 QCOMPARE(object->property("test").toInt(), 2);
2574 emit object->basicSignal();
2575 QCOMPARE(object->property("test").toInt(), 2);
2576 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2577 QCOMPARE(object->property("test").toInt(), 2);
2583 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
2585 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2586 QVERIFY(object != 0);
2588 QCOMPARE(object->property("test").toInt(), 0);
2589 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2590 QCOMPARE(object->property("test").toInt(), 1);
2591 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2592 QCOMPARE(object->property("test").toInt(), 2);
2593 emit object->basicSignal();
2594 QCOMPARE(object->property("test").toInt(), 2);
2595 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2596 QCOMPARE(object->property("test").toInt(), 3);
2601 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
2603 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2604 QVERIFY(object != 0);
2606 QCOMPARE(object->property("test").toInt(), 0);
2607 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2608 QCOMPARE(object->property("test").toInt(), 1);
2609 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2610 QCOMPARE(object->property("test").toInt(), 2);
2611 emit object->basicSignal();
2612 QCOMPARE(object->property("test").toInt(), 2);
2613 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2614 QCOMPARE(object->property("test").toInt(), 3);
2620 class OwnershipObject : public QObject
2624 OwnershipObject() { object = new QObject; }
2626 QPointer<QObject> object;
2629 QObject *getObject() { return object; }
2632 void tst_qdeclarativeecmascript::ownership()
2634 OwnershipObject own;
2635 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2636 context->setContextObject(&own);
2639 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2641 QVERIFY(own.object != 0);
2643 QObject *object = component.create(context);
2645 engine.collectGarbage();
2647 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2648 QCoreApplication::processEvents();
2650 QVERIFY(own.object == 0);
2655 own.object = new QObject(&own);
2658 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2660 QVERIFY(own.object != 0);
2662 QObject *object = component.create(context);
2664 engine.collectGarbage();
2666 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2667 QCoreApplication::processEvents();
2669 QVERIFY(own.object != 0);
2677 class CppOwnershipReturnValue : public QObject
2681 CppOwnershipReturnValue() : value(0) {}
2682 ~CppOwnershipReturnValue() { delete value; }
2684 Q_INVOKABLE QObject *create() {
2685 value = new QObject;
2686 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2690 Q_INVOKABLE MyQmlObject *createQmlObject() {
2691 MyQmlObject *rv = new MyQmlObject;
2696 QPointer<QObject> value;
2700 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2701 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2703 CppOwnershipReturnValue source;
2706 QDeclarativeEngine engine;
2707 engine.rootContext()->setContextProperty("source", &source);
2709 QVERIFY(source.value == 0);
2711 QDeclarativeComponent component(&engine);
2712 component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2714 QObject *object = component.create();
2716 QVERIFY(object != 0);
2717 QVERIFY(source.value != 0);
2722 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2723 QCoreApplication::processEvents();
2725 QVERIFY(source.value != 0);
2729 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2731 CppOwnershipReturnValue source;
2734 QDeclarativeEngine engine;
2735 engine.rootContext()->setContextProperty("source", &source);
2737 QVERIFY(source.value == 0);
2739 QDeclarativeComponent component(&engine);
2740 component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2742 QObject *object = component.create();
2744 QVERIFY(object != 0);
2745 QVERIFY(source.value != 0);
2750 engine.collectGarbage();
2751 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2752 QCoreApplication::processEvents();
2754 QVERIFY(source.value == 0);
2757 class QListQObjectMethodsObject : public QObject
2761 QListQObjectMethodsObject() {
2762 m_objects.append(new MyQmlObject());
2763 m_objects.append(new MyQmlObject());
2766 ~QListQObjectMethodsObject() {
2767 qDeleteAll(m_objects);
2771 QList<QObject *> getObjects() { return m_objects; }
2774 QList<QObject *> m_objects;
2777 // Tests that returning a QList<QObject*> from a method works
2778 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2780 QListQObjectMethodsObject obj;
2781 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2782 context->setContextObject(&obj);
2784 QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
2786 QObject *object = component.create(context);
2788 QCOMPARE(object->property("test").toInt(), 2);
2789 QCOMPARE(object->property("test2").toBool(), true);
2796 void tst_qdeclarativeecmascript::strictlyEquals()
2798 QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
2800 QObject *object = component.create();
2801 QVERIFY(object != 0);
2803 QCOMPARE(object->property("test1").toBool(), true);
2804 QCOMPARE(object->property("test2").toBool(), true);
2805 QCOMPARE(object->property("test3").toBool(), true);
2806 QCOMPARE(object->property("test4").toBool(), true);
2807 QCOMPARE(object->property("test5").toBool(), true);
2808 QCOMPARE(object->property("test6").toBool(), true);
2809 QCOMPARE(object->property("test7").toBool(), true);
2810 QCOMPARE(object->property("test8").toBool(), true);
2815 void tst_qdeclarativeecmascript::compiled()
2817 QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
2819 QObject *object = component.create();
2820 QVERIFY(object != 0);
2822 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2823 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2824 QCOMPARE(object->property("test3").toBool(), true);
2825 QCOMPARE(object->property("test4").toBool(), false);
2826 QCOMPARE(object->property("test5").toBool(), false);
2827 QCOMPARE(object->property("test6").toBool(), true);
2829 QCOMPARE(object->property("test7").toInt(), 185);
2830 QCOMPARE(object->property("test8").toInt(), 167);
2831 QCOMPARE(object->property("test9").toBool(), true);
2832 QCOMPARE(object->property("test10").toBool(), false);
2833 QCOMPARE(object->property("test11").toBool(), false);
2834 QCOMPARE(object->property("test12").toBool(), true);
2836 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2837 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2838 QCOMPARE(object->property("test15").toBool(), false);
2839 QCOMPARE(object->property("test16").toBool(), true);
2841 QCOMPARE(object->property("test17").toInt(), 5);
2842 QCOMPARE(object->property("test18").toReal(), qreal(176));
2843 QCOMPARE(object->property("test19").toInt(), 7);
2844 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2845 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2846 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2847 QCOMPARE(object->property("test23").toBool(), true);
2848 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2849 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2854 // Test that numbers assigned in bindings as strings work consistently
2855 void tst_qdeclarativeecmascript::numberAssignment()
2857 QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
2859 QObject *object = component.create();
2860 QVERIFY(object != 0);
2862 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2863 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2864 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2865 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2866 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2868 QCOMPARE(object->property("test5"), QVariant((int)7));
2869 QCOMPARE(object->property("test6"), QVariant((int)7));
2870 QCOMPARE(object->property("test7"), QVariant((int)6));
2871 QCOMPARE(object->property("test8"), QVariant((int)6));
2873 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2874 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2875 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2876 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2881 void tst_qdeclarativeecmascript::propertySplicing()
2883 QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
2885 QObject *object = component.create();
2886 QVERIFY(object != 0);
2888 QCOMPARE(object->property("test").toBool(), true);
2894 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2896 QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
2898 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2899 QVERIFY(object != 0);
2901 MyQmlObject::MyType type;
2902 type.value = 0x8971123;
2903 emit object->signalWithUnknownType(type);
2905 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2907 QCOMPARE(result.value, type.value);
2913 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2915 QTest::addColumn<QString>("expression");
2916 QTest::addColumn<QString>("compare");
2918 QString compareStrict("(function(a, b) { return a === b; })");
2919 QTest::newRow("true") << "true" << compareStrict;
2920 QTest::newRow("undefined") << "undefined" << compareStrict;
2921 QTest::newRow("null") << "null" << compareStrict;
2922 QTest::newRow("123") << "123" << compareStrict;
2923 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2925 QString comparePropertiesStrict(
2927 " if (typeof b != 'object')"
2929 " var props = Object.getOwnPropertyNames(b);"
2930 " for (var i = 0; i < props.length; ++i) {"
2931 " var p = props[i];"
2932 " return arguments.callee(a[p], b[p]);"
2935 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2936 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2939 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2941 QFETCH(QString, expression);
2942 QFETCH(QString, compare);
2944 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2945 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2946 QVERIFY(object != 0);
2948 QJSValue value = engine.evaluate(expression);
2949 QVERIFY(!engine.hasUncaughtException());
2950 object->setProperty("expression", expression);
2951 object->setProperty("compare", compare);
2952 object->setProperty("pass", false);
2954 emit object->signalWithVariant(QVariant::fromValue(value));
2955 QVERIFY(object->property("pass").toBool());
2958 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2960 signalWithJSValueInVariant_data();
2963 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2965 QFETCH(QString, expression);
2966 QFETCH(QString, compare);
2968 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2969 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2970 QVERIFY(object != 0);
2973 QJSValue value = engine2.evaluate(expression);
2974 QVERIFY(!engine2.hasUncaughtException());
2975 object->setProperty("expression", expression);
2976 object->setProperty("compare", compare);
2977 object->setProperty("pass", false);
2979 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2980 emit object->signalWithVariant(QVariant::fromValue(value));
2981 QVERIFY(!object->property("pass").toBool());
2984 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2986 signalWithJSValueInVariant_data();
2989 void tst_qdeclarativeecmascript::signalWithQJSValue()
2991 QFETCH(QString, expression);
2992 QFETCH(QString, compare);
2994 QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
2995 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2996 QVERIFY(object != 0);
2998 QJSValue value = engine.evaluate(expression);
2999 QVERIFY(!engine.hasUncaughtException());
3000 object->setProperty("expression", expression);
3001 object->setProperty("compare", compare);
3002 object->setProperty("pass", false);
3004 emit object->signalWithQJSValue(value);
3006 QVERIFY(object->property("pass").toBool());
3007 QVERIFY(object->qjsvalue().strictlyEquals(value));
3010 void tst_qdeclarativeecmascript::moduleApi_data()
3012 QTest::addColumn<QUrl>("testfile");
3013 QTest::addColumn<QString>("errorMessage");
3014 QTest::addColumn<QStringList>("warningMessages");
3015 QTest::addColumn<QStringList>("readProperties");
3016 QTest::addColumn<QVariantList>("readExpectedValues");
3017 QTest::addColumn<QStringList>("writeProperties");
3018 QTest::addColumn<QVariantList>("writeValues");
3019 QTest::addColumn<QStringList>("readBackProperties");
3020 QTest::addColumn<QVariantList>("readBackExpectedValues");
3022 QTest::newRow("qobject, register + read + method")
3023 << testFileUrl("moduleapi/qobjectModuleApi.qml")
3026 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
3027 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
3028 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
3034 QTest::newRow("script, register + read")
3035 << testFileUrl("moduleapi/scriptModuleApi.qml")
3038 << (QStringList() << "scriptTest")
3039 << (QVariantList() << 13)
3045 QTest::newRow("qobject, caching + read")
3046 << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
3049 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3050 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3056 QTest::newRow("script, caching + read")
3057 << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
3060 << (QStringList() << "scriptTest")
3061 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3067 QTest::newRow("qobject, writing + readonly constraints")
3068 << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
3070 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3071 << (QStringList() << "readOnlyProperty" << "writableProperty")
3072 << (QVariantList() << 20 << 50)
3073 << (QStringList() << "firstProperty" << "writableProperty")
3074 << (QVariantList() << 30 << 30)
3075 << (QStringList() << "readOnlyProperty" << "writableProperty")
3076 << (QVariantList() << 20 << 30);
3078 QTest::newRow("script, writing + readonly constraints")
3079 << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
3081 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3082 << (QStringList() << "readBack" << "unchanged")
3083 << (QVariantList() << 13 << 42)
3084 << (QStringList() << "firstProperty" << "secondProperty")
3085 << (QVariantList() << 30 << 30)
3086 << (QStringList() << "readBack" << "unchanged")
3087 << (QVariantList() << 30 << 42);
3089 QTest::newRow("qobject module API enum values in JS")
3090 << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
3093 << (QStringList() << "enumValue" << "enumMethod")
3094 << (QVariantList() << 42 << 30)
3100 QTest::newRow("qobject, invalid major version fail")
3101 << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
3102 << QString("QDeclarativeComponent: Component is not ready")
3111 QTest::newRow("qobject, invalid minor version fail")
3112 << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
3113 << QString("QDeclarativeComponent: Component is not ready")
3123 void tst_qdeclarativeecmascript::moduleApi()
3125 QFETCH(QUrl, testfile);
3126 QFETCH(QString, errorMessage);
3127 QFETCH(QStringList, warningMessages);
3128 QFETCH(QStringList, readProperties);
3129 QFETCH(QVariantList, readExpectedValues);
3130 QFETCH(QStringList, writeProperties);
3131 QFETCH(QVariantList, writeValues);
3132 QFETCH(QStringList, readBackProperties);
3133 QFETCH(QVariantList, readBackExpectedValues);
3135 QDeclarativeComponent component(&engine, testfile);
3137 if (!errorMessage.isEmpty())
3138 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3140 if (warningMessages.size())
3141 foreach (const QString &warning, warningMessages)
3142 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3144 QObject *object = component.create();
3145 if (!errorMessage.isEmpty()) {
3146 QVERIFY(object == 0);
3148 QVERIFY(object != 0);
3149 for (int i = 0; i < readProperties.size(); ++i)
3150 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3151 for (int i = 0; i < writeProperties.size(); ++i)
3152 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3153 for (int i = 0; i < readBackProperties.size(); ++i)
3154 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3159 void tst_qdeclarativeecmascript::importScripts_data()
3161 QTest::addColumn<QUrl>("testfile");
3162 QTest::addColumn<QString>("errorMessage");
3163 QTest::addColumn<QStringList>("warningMessages");
3164 QTest::addColumn<QStringList>("propertyNames");
3165 QTest::addColumn<QVariantList>("propertyValues");
3167 QTest::newRow("basic functionality")
3168 << testFileUrl("jsimport/testImport.qml")
3171 << (QStringList() << QLatin1String("importedScriptStringValue")
3172 << QLatin1String("importedScriptFunctionValue")
3173 << QLatin1String("importedModuleAttachedPropertyValue")
3174 << QLatin1String("importedModuleEnumValue"))
3175 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3180 QTest::newRow("import scoping")
3181 << testFileUrl("jsimport/testImportScoping.qml")
3184 << (QStringList() << QLatin1String("componentError"))
3185 << (QVariantList() << QVariant(5));
3187 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3188 << testFileUrl("jsimportfail/failOne.qml")
3190 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3191 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3192 << (QVariantList() << QVariant(QString()));
3194 QTest::newRow("javascript imports in an import should be private to the import scope")
3195 << testFileUrl("jsimportfail/failTwo.qml")
3197 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3198 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3199 << (QVariantList() << QVariant(QString()));
3201 QTest::newRow("module imports in an import should be private to the import scope")
3202 << testFileUrl("jsimportfail/failThree.qml")
3204 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3205 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3206 << (QVariantList() << QVariant(false));
3208 QTest::newRow("typenames in an import should be private to the import scope")
3209 << testFileUrl("jsimportfail/failFour.qml")
3211 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3212 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3213 << (QVariantList() << QVariant(0));
3215 QTest::newRow("import with imports has it's own activation scope")
3216 << testFileUrl("jsimportfail/failFive.qml")
3218 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component")))
3219 << (QStringList() << QLatin1String("componentError"))
3220 << (QVariantList() << QVariant(0));
3222 QTest::newRow("import pragma library script")
3223 << testFileUrl("jsimport/testImportPragmaLibrary.qml")
3226 << (QStringList() << QLatin1String("testValue"))
3227 << (QVariantList() << QVariant(31));
3229 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3230 << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
3232 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3233 << (QStringList() << QLatin1String("testValue"))
3234 << (QVariantList() << QVariant(0));
3236 QTest::newRow("import pragma library script which has an import")
3237 << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
3240 << (QStringList() << QLatin1String("testValue"))
3241 << (QVariantList() << QVariant(55));
3243 QTest::newRow("import pragma library script which has a pragma library import")
3244 << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3247 << (QStringList() << QLatin1String("testValue"))
3248 << (QVariantList() << QVariant(18));
3251 void tst_qdeclarativeecmascript::importScripts()
3253 QFETCH(QUrl, testfile);
3254 QFETCH(QString, errorMessage);
3255 QFETCH(QStringList, warningMessages);
3256 QFETCH(QStringList, propertyNames);
3257 QFETCH(QVariantList, propertyValues);
3259 QDeclarativeComponent component(&engine, testfile);
3261 if (!errorMessage.isEmpty())
3262 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3264 if (warningMessages.size())
3265 foreach (const QString &warning, warningMessages)
3266 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3268 QObject *object = component.create();
3269 if (!errorMessage.isEmpty()) {
3270 QVERIFY(object == 0);
3272 QVERIFY(object != 0);
3273 for (int i = 0; i < propertyNames.size(); ++i)
3274 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3279 void tst_qdeclarativeecmascript::scarceResources_other()
3281 /* These tests require knowledge of state, since we test values after
3282 performing signal or function invocation. */
3284 QPixmap origPixmap(100, 100);
3285 origPixmap.fill(Qt::blue);
3286 QString srp_name, expectedWarning;
3287 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3288 ScarceResourceObject *eo = 0;
3290 QObject *object = 0;
3292 /* property var semantics */
3294 // test that scarce resources are handled properly in signal invocation
3295 QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
3296 object = varComponentTen.create();
3297 srsc = object->findChild<QObject*>("srsc");
3299 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3300 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3301 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3302 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3303 QMetaObject::invokeMethod(srsc, "testSignal");
3304 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3305 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3306 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3307 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3308 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3309 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3310 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3311 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3312 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3313 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3316 // test that scarce resources are handled properly from js functions in qml files
3317 QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
3318 object = varComponentEleven.create();
3319 QVERIFY(object != 0);
3320 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3321 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3322 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3323 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3324 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3325 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3326 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3327 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3328 QMetaObject::invokeMethod(object, "releaseScarceResource");
3329 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3330 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3331 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3332 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3335 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3336 QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
3337 object = varComponentTwelve.create();
3338 QVERIFY(object != 0);
3339 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3340 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3341 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3342 srp_name = object->property("srp_name").toString();
3343 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3344 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3345 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3346 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3347 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3348 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3349 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3352 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3353 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3354 QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
3355 object = varComponentThirteen.create();
3356 QVERIFY(object != 0);
3357 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3358 QMetaObject::invokeMethod(object, "assignVarProperty");
3359 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3360 QMetaObject::invokeMethod(object, "deassignVarProperty");
3361 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3364 /* property variant semantics */
3366 // test that scarce resources are handled properly in signal invocation
3367 QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
3368 object = variantComponentTen.create();
3369 QVERIFY(object != 0);
3370 srsc = object->findChild<QObject*>("srsc");
3372 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3373 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3374 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3375 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3376 QMetaObject::invokeMethod(srsc, "testSignal");
3377 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3378 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3379 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3380 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3381 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3382 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3383 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3384 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3385 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3386 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3389 // test that scarce resources are handled properly from js functions in qml files
3390 QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
3391 object = variantComponentEleven.create();
3392 QVERIFY(object != 0);
3393 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3394 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3395 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3396 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3397 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3398 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3399 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3400 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3401 QMetaObject::invokeMethod(object, "releaseScarceResource");
3402 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3403 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3404 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3405 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3408 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3409 QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
3410 object = variantComponentTwelve.create();
3411 QVERIFY(object != 0);
3412 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3413 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3414 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3415 srp_name = object->property("srp_name").toString();
3416 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3417 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3418 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3419 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3420 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3421 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3422 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3426 void tst_qdeclarativeecmascript::scarceResources_data()
3428 QTest::addColumn<QUrl>("qmlFile");
3429 QTest::addColumn<bool>("readDetachStatus");
3430 QTest::addColumn<bool>("expectedDetachStatus");
3431 QTest::addColumn<QStringList>("propertyNames");
3432 QTest::addColumn<QVariantList>("expectedValidity");
3433 QTest::addColumn<QVariantList>("expectedValues");
3434 QTest::addColumn<QStringList>("expectedErrors");
3436 QPixmap origPixmap(100, 100);
3437 origPixmap.fill(Qt::blue);
3439 /* property var semantics */
3441 // in the following three cases, the instance created from the component
3442 // has a property which is a copy of the scarce resource; hence, the
3443 // resource should NOT be detached prior to deletion of the object instance,
3444 // unless the resource is destroyed explicitly.
3445 QTest::newRow("var: import scarce resource copy directly")
3446 << testFileUrl("scarceResourceCopy.var.qml")
3448 << false // won't be detached, because assigned to property and not explicitly released
3449 << (QStringList() << QLatin1String("scarceResourceCopy"))
3450 << (QList<QVariant>() << true)
3451 << (QList<QVariant>() << origPixmap)
3454 QTest::newRow("var: import scarce resource copy from JS")
3455 << testFileUrl("scarceResourceCopyFromJs.var.qml")
3457 << false // won't be detached, because assigned to property and not explicitly released
3458 << (QStringList() << QLatin1String("scarceResourceCopy"))
3459 << (QList<QVariant>() << true)
3460 << (QList<QVariant>() << origPixmap)
3463 QTest::newRow("var: import released scarce resource copy from JS")
3464 << testFileUrl("scarceResourceDestroyedCopy.var.qml")
3466 << true // explicitly released, so it will be detached
3467 << (QStringList() << QLatin1String("scarceResourceCopy"))
3468 << (QList<QVariant>() << false)
3469 << (QList<QVariant>() << QVariant())
3472 // in the following three cases, no other copy should exist in memory,
3473 // and so it should be detached (unless explicitly preserved).
3474 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3475 << testFileUrl("scarceResourceTest.var.qml")
3477 << true // auto released, so it will be detached
3478 << (QStringList() << QLatin1String("scarceResourceTest"))
3479 << (QList<QVariant>() << true)
3480 << (QList<QVariant>() << QVariant(100))
3482 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3483 << testFileUrl("scarceResourceTestPreserve.var.qml")
3485 << false // won't be detached because we explicitly preserve it
3486 << (QStringList() << QLatin1String("scarceResourceTest"))
3487 << (QList<QVariant>() << true)
3488 << (QList<QVariant>() << QVariant(100))
3490 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3491 << testFileUrl("scarceResourceTestMultiple.var.qml")
3493 << true // will be detached because all resources were released manually or automatically.
3494 << (QStringList() << QLatin1String("scarceResourceTest"))
3495 << (QList<QVariant>() << true)
3496 << (QList<QVariant>() << QVariant(100))
3499 // In the following three cases, test that scarce resources are handled
3500 // correctly for imports.
3501 QTest::newRow("var: import with no binding")
3502 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3503 << false // cannot check detach status.
3506 << QList<QVariant>()
3507 << QList<QVariant>()
3509 QTest::newRow("var: import with binding without explicit preserve")
3510 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3513 << (QStringList() << QLatin1String("scarceResourceCopy"))
3514 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3515 << (QList<QVariant>() << QVariant())
3517 QTest::newRow("var: import with explicit release after binding evaluation")
3518 << testFileUrl("scarceResourceCopyImport.var.qml")
3521 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3522 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3523 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3525 QTest::newRow("var: import with different js objects")
3526 << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
3529 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3530 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3531 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3533 QTest::newRow("var: import with different js objects and explicit release")
3534 << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
3537 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3538 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3539 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3541 QTest::newRow("var: import with same js objects and explicit release")
3542 << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
3545 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3546 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3547 << (QList<QVariant>() << QVariant() << QVariant())
3549 QTest::newRow("var: binding with same js objects and explicit release")
3550 << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
3553 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3554 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3555 << (QList<QVariant>() << QVariant() << QVariant())
3559 /* property variant semantics */
3561 // in the following three cases, the instance created from the component
3562 // has a property which is a copy of the scarce resource; hence, the
3563 // resource should NOT be detached prior to deletion of the object instance,
3564 // unless the resource is destroyed explicitly.
3565 QTest::newRow("variant: import scarce resource copy directly")
3566 << testFileUrl("scarceResourceCopy.variant.qml")
3568 << false // won't be detached, because assigned to property and not explicitly released
3569 << (QStringList() << QLatin1String("scarceResourceCopy"))
3570 << (QList<QVariant>() << true)
3571 << (QList<QVariant>() << origPixmap)
3574 QTest::newRow("variant: import scarce resource copy from JS")
3575 << testFileUrl("scarceResourceCopyFromJs.variant.qml")
3577 << false // won't be detached, because assigned to property and not explicitly released
3578 << (QStringList() << QLatin1String("scarceResourceCopy"))
3579 << (QList<QVariant>() << true)
3580 << (QList<QVariant>() << origPixmap)
3583 QTest::newRow("variant: import released scarce resource copy from JS")
3584 << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
3586 << true // explicitly released, so it will be detached
3587 << (QStringList() << QLatin1String("scarceResourceCopy"))
3588 << (QList<QVariant>() << false)
3589 << (QList<QVariant>() << QVariant())
3592 // in the following three cases, no other copy should exist in memory,
3593 // and so it should be detached (unless explicitly preserved).
3594 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3595 << testFileUrl("scarceResourceTest.variant.qml")
3597 << true // auto released, so it will be detached
3598 << (QStringList() << QLatin1String("scarceResourceTest"))
3599 << (QList<QVariant>() << true)
3600 << (QList<QVariant>() << QVariant(100))
3602 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3603 << testFileUrl("scarceResourceTestPreserve.variant.qml")
3605 << false // won't be detached because we explicitly preserve it
3606 << (QStringList() << QLatin1String("scarceResourceTest"))
3607 << (QList<QVariant>() << true)
3608 << (QList<QVariant>() << QVariant(100))
3610 QTest::newRow("variant: import multiple scarce resources")
3611 << testFileUrl("scarceResourceTestMultiple.variant.qml")
3613 << true // will be detached because all resources were released manually or automatically.
3614 << (QStringList() << QLatin1String("scarceResourceTest"))
3615 << (QList<QVariant>() << true)
3616 << (QList<QVariant>() << QVariant(100))
3619 // In the following three cases, test that scarce resources are handled
3620 // correctly for imports.
3621 QTest::newRow("variant: import with no binding")
3622 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3623 << false // cannot check detach status.
3626 << QList<QVariant>()
3627 << QList<QVariant>()
3629 QTest::newRow("variant: import with binding without explicit preserve")
3630 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3633 << (QStringList() << QLatin1String("scarceResourceCopy"))
3634 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3635 << (QList<QVariant>() << QVariant())
3637 QTest::newRow("variant: import with explicit release after binding evaluation")
3638 << testFileUrl("scarceResourceCopyImport.variant.qml")
3641 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3642 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3643 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3647 void tst_qdeclarativeecmascript::scarceResources()
3649 QFETCH(QUrl, qmlFile);
3650 QFETCH(bool, readDetachStatus);
3651 QFETCH(bool, expectedDetachStatus);
3652 QFETCH(QStringList, propertyNames);
3653 QFETCH(QVariantList, expectedValidity);
3654 QFETCH(QVariantList, expectedValues);
3655 QFETCH(QStringList, expectedErrors);
3657 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3658 ScarceResourceObject *eo = 0;
3659 QObject *object = 0;
3661 QDeclarativeComponent c(&engine, qmlFile);
3662 object = c.create();
3663 QVERIFY(object != 0);
3664 for (int i = 0; i < propertyNames.size(); ++i) {
3665 QString prop = propertyNames.at(i);
3666 bool validity = expectedValidity.at(i).toBool();
3667 QVariant value = expectedValues.at(i);
3669 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3670 if (value.type() == QVariant::Int) {
3671 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3672 } else if (value.type() == QVariant::Pixmap) {
3673 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3677 if (readDetachStatus) {
3678 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3679 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3682 QVERIFY(ep->scarceResources.isEmpty());
3686 void tst_qdeclarativeecmascript::propertyChangeSlots()
3688 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3689 QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
3690 QObject *object = component.create();
3691 QVERIFY(object != 0);
3694 // ensure that invalid property names fail properly.
3695 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3696 QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
3697 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3698 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3699 object = e1.create();
3700 QVERIFY(object == 0);
3703 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3704 QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
3705 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3706 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3707 object = e2.create();
3708 QVERIFY(object == 0);
3711 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3712 QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
3713 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3714 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3715 object = e3.create();
3716 QVERIFY(object == 0);
3719 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3720 QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
3721 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3722 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3723 object = e4.create();
3724 QVERIFY(object == 0);
3728 void tst_qdeclarativeecmascript::propertyVar_data()
3730 QTest::addColumn<QUrl>("qmlFile");
3733 QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
3734 QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
3735 QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
3736 QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
3737 QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
3738 QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
3739 QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
3740 QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
3741 QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
3742 QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
3745 void tst_qdeclarativeecmascript::propertyVar()
3747 QFETCH(QUrl, qmlFile);
3749 QDeclarativeComponent component(&engine, qmlFile);
3750 QObject *object = component.create();
3751 QVERIFY(object != 0);
3753 QCOMPARE(object->property("test").toBool(), true);
3758 // Tests that we can write QVariant values to var properties from C++
3759 void tst_qdeclarativeecmascript::propertyVarCpp()
3761 QObject *object = 0;
3763 // ensure that writing to and reading from a var property from cpp works as required.
3764 // Literal values stored in var properties can be read and written as QVariants
3765 // of a specific type, whereas object values are read as QVariantMaps.
3766 QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
3767 object = component.create();
3768 QVERIFY(object != 0);
3769 // assign int to property var that currently has int assigned
3770 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3771 QCOMPARE(object->property("varBound"), QVariant(15));
3772 QCOMPARE(object->property("intBound"), QVariant(15));
3773 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3774 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3775 // assign string to property var that current has bool assigned
3776 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3777 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3778 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3779 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3780 // now enforce behaviour when accessing JavaScript objects from cpp.
3781 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3785 static void gc(QDeclarativeEngine &engine)
3787 engine.collectGarbage();
3788 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
3789 QCoreApplication::processEvents();
3792 void tst_qdeclarativeecmascript::propertyVarOwnership()
3794 // Referenced JS objects are not collected
3796 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
3797 QObject *object = component.create();
3798 QVERIFY(object != 0);
3799 QCOMPARE(object->property("test").toBool(), false);
3800 QMetaObject::invokeMethod(object, "runTest");
3801 QCOMPARE(object->property("test").toBool(), true);
3804 // Referenced JS objects are not collected
3806 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
3807 QObject *object = component.create();
3808 QVERIFY(object != 0);
3809 QCOMPARE(object->property("test").toBool(), false);
3810 QMetaObject::invokeMethod(object, "runTest");
3811 QCOMPARE(object->property("test").toBool(), true);
3814 // Qt objects are not collected until they've been dereferenced
3816 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
3817 QObject *object = component.create();
3818 QVERIFY(object != 0);
3820 QCOMPARE(object->property("test2").toBool(), false);
3821 QCOMPARE(object->property("test2").toBool(), false);
3823 QMetaObject::invokeMethod(object, "runTest");
3824 QCOMPARE(object->property("test1").toBool(), true);
3826 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3827 QVERIFY(!referencedObject.isNull());
3829 QVERIFY(!referencedObject.isNull());
3831 QMetaObject::invokeMethod(object, "runTest2");
3832 QCOMPARE(object->property("test2").toBool(), true);
3834 QVERIFY(referencedObject.isNull());
3838 // Self reference does not prevent Qt object collection
3840 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
3841 QObject *object = component.create();
3842 QVERIFY(object != 0);
3844 QCOMPARE(object->property("test").toBool(), true);
3846 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3847 QVERIFY(!referencedObject.isNull());
3849 QVERIFY(!referencedObject.isNull());
3851 QMetaObject::invokeMethod(object, "runTest");
3853 QVERIFY(referencedObject.isNull());
3859 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3861 // The childObject has a reference to a different QObject. We want to ensure
3862 // that the different item will not be cleaned up until required. IE, the childObject
3863 // has implicit ownership of the constructed QObject.
3864 QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
3865 QObject *object = component.create();
3866 QVERIFY(object != 0);
3867 QMetaObject::invokeMethod(object, "assignCircular");
3868 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3869 QCoreApplication::processEvents();
3870 QObject *rootObject = object->property("vp").value<QObject*>();
3871 QVERIFY(rootObject != 0);
3872 QObject *childObject = rootObject->findChild<QObject*>("text");
3873 QVERIFY(childObject != 0);
3874 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3875 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3876 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3877 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3878 QVERIFY(!qobjectGuard.isNull());
3879 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3880 QCoreApplication::processEvents();
3881 QVERIFY(!qobjectGuard.isNull());
3882 QMetaObject::invokeMethod(object, "deassignCircular");
3883 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3884 QCoreApplication::processEvents();
3885 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3889 void tst_qdeclarativeecmascript::propertyVarReparent()
3891 // ensure that nothing breaks if we re-parent objects
3892 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3893 QObject *object = component.create();
3894 QVERIFY(object != 0);
3895 QMetaObject::invokeMethod(object, "assignVarProp");
3896 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3897 QCoreApplication::processEvents();
3898 QObject *rect = object->property("vp").value<QObject*>();
3899 QObject *text = rect->findChild<QObject*>("textOne");
3900 QObject *text2 = rect->findChild<QObject*>("textTwo");
3901 QWeakPointer<QObject> rectGuard(rect);
3902 QWeakPointer<QObject> textGuard(text);
3903 QWeakPointer<QObject> text2Guard(text2);
3904 QVERIFY(!rectGuard.isNull());
3905 QVERIFY(!textGuard.isNull());
3906 QVERIFY(!text2Guard.isNull());
3907 QCOMPARE(text->property("textCanary").toInt(), 11);
3908 QCOMPARE(text2->property("textCanary").toInt(), 12);
3909 // now construct an image which we will reparent.
3910 QMetaObject::invokeMethod(text2, "constructQObject");
3911 QObject *image = text2->property("vp").value<QObject*>();
3912 QWeakPointer<QObject> imageGuard(image);
3913 QVERIFY(!imageGuard.isNull());
3914 QCOMPARE(image->property("imageCanary").toInt(), 13);
3915 // now reparent the "Image" object (currently, it has JS ownership)
3916 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3917 QMetaObject::invokeMethod(text2, "deassignVp");
3918 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3919 QCoreApplication::processEvents();
3920 QCOMPARE(text->property("textCanary").toInt(), 11);
3921 QCOMPARE(text2->property("textCanary").toInt(), 22);
3922 QVERIFY(!imageGuard.isNull()); // should still be alive.
3923 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3924 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3925 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3926 QCoreApplication::processEvents();
3927 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3931 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3933 // sometimes reparenting can cause problems
3934 // (eg, if the ctxt is collected, varproperties are no longer available)
3935 // this test ensures that no crash occurs in that situation.
3936 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3937 QObject *object = component.create();
3938 QVERIFY(object != 0);
3939 QMetaObject::invokeMethod(object, "assignVarProp");
3940 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3941 QCoreApplication::processEvents();
3942 QObject *rect = object->property("vp").value<QObject*>();
3943 QObject *text = rect->findChild<QObject*>("textOne");
3944 QObject *text2 = rect->findChild<QObject*>("textTwo");
3945 QWeakPointer<QObject> rectGuard(rect);
3946 QWeakPointer<QObject> textGuard(text);
3947 QWeakPointer<QObject> text2Guard(text2);
3948 QVERIFY(!rectGuard.isNull());
3949 QVERIFY(!textGuard.isNull());
3950 QVERIFY(!text2Guard.isNull());
3951 QCOMPARE(text->property("textCanary").toInt(), 11);
3952 QCOMPARE(text2->property("textCanary").toInt(), 12);
3953 // now construct an image which we will reparent.
3954 QMetaObject::invokeMethod(text2, "constructQObject");
3955 QObject *image = text2->property("vp").value<QObject*>();
3956 QWeakPointer<QObject> imageGuard(image);
3957 QVERIFY(!imageGuard.isNull());
3958 QCOMPARE(image->property("imageCanary").toInt(), 13);
3959 // now reparent the "Image" object (currently, it has JS ownership)
3960 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3961 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3962 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3963 QCoreApplication::processEvents();
3964 QVERIFY(!imageGuard.isNull()); // should still be alive.
3965 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3967 QVERIFY(imageGuard.isNull()); // should now be dead.
3970 void tst_qdeclarativeecmascript::propertyVarCircular()
3972 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3973 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
3974 QObject *object = component.create();
3975 QVERIFY(object != 0);
3976 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3977 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3978 QCoreApplication::processEvents();
3979 QCOMPARE(object->property("canaryInt"), QVariant(5));
3980 QVariant canaryResourceVariant = object->property("canaryResource");
3981 QVERIFY(canaryResourceVariant.isValid());
3982 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3983 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3984 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3985 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3986 QCoreApplication::processEvents();
3987 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3988 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3989 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
3990 QCoreApplication::processEvents();
3991 QCOMPARE(object->property("canaryInt"), QVariant(2));
3992 QCOMPARE(object->property("canaryResource"), QVariant(1));
3993 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3997 void tst_qdeclarativeecmascript::propertyVarCircular2()
3999 // track deletion of JS-owned parent item with Cpp-owned child
4000 // where the child has a var property referencing its parent.
4001 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4002 QObject *object = component.create();
4003 QVERIFY(object != 0);
4004 QMetaObject::invokeMethod(object, "assignCircular");
4005 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4006 QCoreApplication::processEvents();
4007 QObject *rootObject = object->property("vp").value<QObject*>();
4008 QVERIFY(rootObject != 0);
4009 QObject *childObject = rootObject->findChild<QObject*>("text");
4010 QVERIFY(childObject != 0);
4011 QWeakPointer<QObject> rootObjectTracker(rootObject);
4012 QVERIFY(!rootObjectTracker.isNull());
4013 QWeakPointer<QObject> childObjectTracker(childObject);
4014 QVERIFY(!childObjectTracker.isNull());
4016 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4017 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4018 QMetaObject::invokeMethod(object, "deassignCircular");
4019 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4020 QCoreApplication::processEvents();
4021 QVERIFY(rootObjectTracker.isNull()); // should have been collected
4022 QVERIFY(childObjectTracker.isNull()); // should have been collected
4026 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
4028 *(int*)(parameter) += 1;
4029 qPersistentDispose(object);
4032 void tst_qdeclarativeecmascript::propertyVarInheritance()
4034 int propertyVarWeakRefCallbackCount = 0;
4036 // enforce behaviour regarding element inheritance - ensure handle disposal.
4037 // The particular component under test here has a chain of references.
4038 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
4039 QObject *object = component.create();
4040 QVERIFY(object != 0);
4041 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
4042 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4043 QCoreApplication::processEvents();
4044 // we want to be able to track when the varProperties array of the last metaobject is disposed
4045 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
4046 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*>();
4047 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
4048 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
4049 v8::Persistent<v8::Value> icoCanaryHandle;
4050 v8::Persistent<v8::Value> ccoCanaryHandle;
4053 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4054 // public function which can return us a handle to something in the varProperties array.
4055 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4056 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4057 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4058 // as the varproperties array of each vmemo still references the resource.
4059 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4060 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4062 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4064 // now we deassign the var prop, which should trigger collection of item subtrees.
4065 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4066 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4067 QCoreApplication::processEvents();
4068 // ensure that there are only weak handles to the underlying varProperties array remaining.
4070 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4072 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4073 // to what remains are weak, all varProperties arrays must have been collected.
4076 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4078 int propertyVarWeakRefCallbackCount = 0;
4080 // The particular component under test here does NOT have a chain of references; the
4081 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4082 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4083 QObject *object = component.create();
4084 QVERIFY(object != 0);
4085 QMetaObject::invokeMethod(object, "assignCircular");
4086 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4087 QCoreApplication::processEvents();
4088 QObject *rootObject = object->property("vp").value<QObject*>();
4089 QVERIFY(rootObject != 0);
4090 QObject *childObject = rootObject->findChild<QObject*>("text");
4091 QVERIFY(childObject != 0);
4092 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4093 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4094 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4097 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4098 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
4099 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4101 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4102 QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
4103 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4105 QMetaObject::invokeMethod(object, "deassignCircular");
4106 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
4107 QCoreApplication::processEvents();
4108 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4112 // Ensure that QObject type conversion works on binding assignment
4113 void tst_qdeclarativeecmascript::elementAssign()
4115 QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
4117 QObject *object = component.create();
4118 QVERIFY(object != 0);
4120 QCOMPARE(object->property("test").toBool(), true);
4126 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4128 QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
4130 QObject *object = component.create();
4131 QVERIFY(object != 0);
4133 QCOMPARE(object->property("test").toBool(), true);
4139 void tst_qdeclarativeecmascript::objectConversion()
4141 QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
4143 QObject *object = component.create();
4144 QVERIFY(object != 0);
4146 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4147 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4154 void tst_qdeclarativeecmascript::booleanConversion()
4156 QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
4158 QObject *object = component.create();
4159 QVERIFY(object != 0);
4161 QCOMPARE(object->property("test_true1").toBool(), true);
4162 QCOMPARE(object->property("test_true2").toBool(), true);
4163 QCOMPARE(object->property("test_true3").toBool(), true);
4164 QCOMPARE(object->property("test_true4").toBool(), true);
4165 QCOMPARE(object->property("test_true5").toBool(), true);
4167 QCOMPARE(object->property("test_false1").toBool(), false);
4168 QCOMPARE(object->property("test_false2").toBool(), false);
4169 QCOMPARE(object->property("test_false3").toBool(), false);
4174 void tst_qdeclarativeecmascript::handleReferenceManagement()
4179 // Linear QObject reference
4180 QDeclarativeEngine hrmEngine;
4181 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
4182 QObject *object = component.create();
4183 QVERIFY(object != 0);
4184 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4185 cro->setEngine(&hrmEngine);
4186 cro->setDtorCount(&dtorCount);
4187 QMetaObject::invokeMethod(object, "createReference");
4189 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4191 hrmEngine.collectGarbage();
4192 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4193 QCoreApplication::processEvents();
4194 QCOMPARE(dtorCount, 3);
4199 // Circular QObject reference
4200 QDeclarativeEngine hrmEngine;
4201 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
4202 QObject *object = component.create();
4203 QVERIFY(object != 0);
4204 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4205 cro->setEngine(&hrmEngine);
4206 cro->setDtorCount(&dtorCount);
4207 QMetaObject::invokeMethod(object, "circularReference");
4209 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4211 hrmEngine.collectGarbage();
4212 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4213 QCoreApplication::processEvents();
4214 QCOMPARE(dtorCount, 3);
4219 // Linear handle reference
4220 QDeclarativeEngine hrmEngine;
4221 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
4222 QObject *object = component.create();
4223 QVERIFY(object != 0);
4224 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4226 crh->setEngine(&hrmEngine);
4227 crh->setDtorCount(&dtorCount);
4228 QMetaObject::invokeMethod(object, "createReference");
4229 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4230 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4231 QVERIFY(first != 0);
4232 QVERIFY(second != 0);
4233 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4234 // now we have to reparent second and make second owned by JS.
4235 second->setParent(0);
4236 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4238 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4240 hrmEngine.collectGarbage();
4241 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4242 QCoreApplication::processEvents();
4243 QCOMPARE(dtorCount, 3);
4248 // Circular handle reference
4249 QDeclarativeEngine hrmEngine;
4250 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
4251 QObject *object = component.create();
4252 QVERIFY(object != 0);
4253 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4255 crh->setEngine(&hrmEngine);
4256 crh->setDtorCount(&dtorCount);
4257 QMetaObject::invokeMethod(object, "circularReference");
4258 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4259 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4260 QVERIFY(first != 0);
4261 QVERIFY(second != 0);
4262 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4263 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4264 // now we have to reparent and change ownership.
4265 first->setParent(0);
4266 second->setParent(0);
4267 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4268 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4270 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4272 hrmEngine.collectGarbage();
4273 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4274 QCoreApplication::processEvents();
4275 QCOMPARE(dtorCount, 3);
4280 // multiple engine interaction - linear reference
4281 QDeclarativeEngine hrmEngine1;
4282 QDeclarativeEngine hrmEngine2;
4283 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4284 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4285 QObject *object1 = component1.create();
4286 QObject *object2 = component2.create();
4287 QVERIFY(object1 != 0);
4288 QVERIFY(object2 != 0);
4289 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4290 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4293 crh1->setEngine(&hrmEngine1);
4294 crh2->setEngine(&hrmEngine2);
4295 crh1->setDtorCount(&dtorCount);
4296 crh2->setDtorCount(&dtorCount);
4297 QMetaObject::invokeMethod(object1, "createReference");
4298 QMetaObject::invokeMethod(object2, "createReference");
4299 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4300 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4301 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4302 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4303 QVERIFY(first1 != 0);
4304 QVERIFY(second1 != 0);
4305 QVERIFY(first2 != 0);
4306 QVERIFY(second2 != 0);
4307 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4308 // now we have to reparent second2 and make second2 owned by JS.
4309 second2->setParent(0);
4310 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4312 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4313 QCoreApplication::processEvents();
4314 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4317 hrmEngine1.collectGarbage();
4318 hrmEngine2.collectGarbage();
4319 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4320 QCoreApplication::processEvents();
4321 QCOMPARE(dtorCount, 6);
4326 // multiple engine interaction - circular reference
4327 QDeclarativeEngine hrmEngine1;
4328 QDeclarativeEngine hrmEngine2;
4329 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4330 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4331 QObject *object1 = component1.create();
4332 QObject *object2 = component2.create();
4333 QVERIFY(object1 != 0);
4334 QVERIFY(object2 != 0);
4335 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4336 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4339 crh1->setEngine(&hrmEngine1);
4340 crh2->setEngine(&hrmEngine2);
4341 crh1->setDtorCount(&dtorCount);
4342 crh2->setDtorCount(&dtorCount);
4343 QMetaObject::invokeMethod(object1, "createReference");
4344 QMetaObject::invokeMethod(object2, "createReference");
4345 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4346 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4347 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4348 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4349 QVERIFY(first1 != 0);
4350 QVERIFY(second1 != 0);
4351 QVERIFY(first2 != 0);
4352 QVERIFY(second2 != 0);
4353 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4354 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4355 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4356 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4357 // now we have to reparent and change ownership to JS.
4358 first1->setParent(0);
4359 second1->setParent(0);
4360 first2->setParent(0);
4361 second2->setParent(0);
4362 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4363 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4364 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4365 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4367 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4368 QCoreApplication::processEvents();
4369 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4372 hrmEngine1.collectGarbage();
4373 hrmEngine2.collectGarbage();
4374 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4375 QCoreApplication::processEvents();
4376 QCOMPARE(dtorCount, 6);
4381 // multiple engine interaction - linear reference with engine deletion
4382 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4383 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4384 QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4385 QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4386 QObject *object1 = component1.create();
4387 QObject *object2 = component2.create();
4388 QVERIFY(object1 != 0);
4389 QVERIFY(object2 != 0);
4390 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4391 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4394 crh1->setEngine(hrmEngine1);
4395 crh2->setEngine(hrmEngine2);
4396 crh1->setDtorCount(&dtorCount);
4397 crh2->setDtorCount(&dtorCount);
4398 QMetaObject::invokeMethod(object1, "createReference");
4399 QMetaObject::invokeMethod(object2, "createReference");
4400 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4401 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4402 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4403 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4404 QVERIFY(first1 != 0);
4405 QVERIFY(second1 != 0);
4406 QVERIFY(first2 != 0);
4407 QVERIFY(second2 != 0);
4408 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4409 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4410 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4411 // now we have to reparent and change ownership to JS.
4412 first1->setParent(crh1);
4413 second1->setParent(0);
4414 first2->setParent(0);
4415 second2->setParent(0);
4416 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4417 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4418 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4420 QCOMPARE(dtorCount, 0);
4423 QCOMPARE(dtorCount, 0);
4426 hrmEngine1->collectGarbage();
4427 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
4428 QCoreApplication::processEvents();
4429 QCOMPARE(dtorCount, 6);
4434 void tst_qdeclarativeecmascript::stringArg()
4436 QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
4437 QObject *object = component.create();
4438 QVERIFY(object != 0);
4439 QMetaObject::invokeMethod(object, "success");
4440 QVERIFY(object->property("returnValue").toBool());
4442 QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4443 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4444 QMetaObject::invokeMethod(object, "failure");
4445 QVERIFY(object->property("returnValue").toBool());
4450 void tst_qdeclarativeecmascript::readonlyDeclaration()
4452 QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
4454 QObject *object = component.create();
4455 QVERIFY(object != 0);
4457 QCOMPARE(object->property("test").toBool(), true);
4462 Q_DECLARE_METATYPE(QList<int>)
4463 Q_DECLARE_METATYPE(QList<qreal>)
4464 Q_DECLARE_METATYPE(QList<bool>)
4465 Q_DECLARE_METATYPE(QList<QString>)
4466 Q_DECLARE_METATYPE(QList<QUrl>)
4467 void tst_qdeclarativeecmascript::sequenceConversionRead()
4470 QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
4471 QDeclarativeComponent component(&engine, qmlFile);
4472 QObject *object = component.create();
4473 QVERIFY(object != 0);
4474 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4477 QMetaObject::invokeMethod(object, "readSequences");
4478 QList<int> intList; intList << 1 << 2 << 3 << 4;
4479 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4480 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4481 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4482 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4483 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4484 QList<bool> boolList; boolList << true << false << true << false;
4485 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4486 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4487 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4488 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4489 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4490 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4491 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4492 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4493 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4494 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4495 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4497 QMetaObject::invokeMethod(object, "readSequenceElements");
4498 QCOMPARE(object->property("intVal").toInt(), 2);
4499 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4500 QCOMPARE(object->property("boolVal").toBool(), false);
4501 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4502 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4503 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4505 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4506 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4508 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4509 QDeclarativeProperty seqProp(seq, "intListProperty");
4510 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4511 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4512 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4514 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4515 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4521 QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
4522 QDeclarativeComponent component(&engine, qmlFile);
4523 QObject *object = component.create();
4524 QVERIFY(object != 0);
4525 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4528 // we haven't registered QList<QPoint> as a sequence type.
4529 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4530 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4531 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4532 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4534 QMetaObject::invokeMethod(object, "performTest");
4536 // QList<QPoint> has not been registered as a sequence type.
4537 QCOMPARE(object->property("pointListLength").toInt(), 0);
4538 QVERIFY(!object->property("pointList").isValid());
4539 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4540 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4541 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4547 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4550 QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
4551 QDeclarativeComponent component(&engine, qmlFile);
4552 QObject *object = component.create();
4553 QVERIFY(object != 0);
4554 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4557 QMetaObject::invokeMethod(object, "writeSequences");
4558 QCOMPARE(object->property("success").toBool(), true);
4560 QMetaObject::invokeMethod(object, "writeSequenceElements");
4561 QCOMPARE(object->property("success").toBool(), true);
4563 QMetaObject::invokeMethod(object, "writeOtherElements");
4564 QCOMPARE(object->property("success").toBool(), true);
4566 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4567 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4573 QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
4574 QDeclarativeComponent component(&engine, qmlFile);
4575 QObject *object = component.create();
4576 QVERIFY(object != 0);
4577 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4580 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4581 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4582 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4584 QMetaObject::invokeMethod(object, "performTest");
4586 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4587 QCOMPARE(seq->pointListProperty(), pointList);
4593 void tst_qdeclarativeecmascript::sequenceConversionArray()
4595 // ensure that in JS the returned sequences act just like normal JS Arrays.
4596 QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
4597 QDeclarativeComponent component(&engine, qmlFile);
4598 QObject *object = component.create();
4599 QVERIFY(object != 0);
4600 QMetaObject::invokeMethod(object, "indexedAccess");
4601 QVERIFY(object->property("success").toBool());
4602 QMetaObject::invokeMethod(object, "arrayOperations");
4603 QVERIFY(object->property("success").toBool());
4604 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4605 QVERIFY(object->property("success").toBool());
4606 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4607 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4612 void tst_qdeclarativeecmascript::sequenceConversionIndexes()
4614 // ensure that we gracefully fail if unsupported index values are specified.
4615 // Qt container classes only support non-negative, signed integer index values.
4616 QUrl qmlFile = testFileUrl("sequenceConversion.indexes.qml");
4617 QDeclarativeComponent component(&engine, qmlFile);
4618 QObject *object = component.create();
4619 QVERIFY(object != 0);
4620 QString w1 = qmlFile.toString() + QLatin1String(":34: Index out of range during length set");
4621 QString w2 = qmlFile.toString() + QLatin1String(":41: Index out of range during indexed set");
4622 QString w3 = qmlFile.toString() + QLatin1String(":48: Index out of range during indexed get");
4623 QString w4 = qmlFile.toString() + QLatin1String(":78: std::bad_alloc during length set");
4624 QString w5 = qmlFile.toString() + QLatin1String(":83: std::bad_alloc during indexed set");
4625 QTest::ignoreMessage(QtWarningMsg, qPrintable(w1));
4626 QTest::ignoreMessage(QtWarningMsg, qPrintable(w2));
4627 QTest::ignoreMessage(QtWarningMsg, qPrintable(w3));
4628 QTest::ignoreMessage(QtWarningMsg, qPrintable(w4));
4629 QTest::ignoreMessage(QtWarningMsg, qPrintable(w5));
4630 QMetaObject::invokeMethod(object, "indexedAccess");
4631 QVERIFY(object->property("success").toBool());
4635 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4637 // ensure that sequence conversion operations work correctly in a worker thread
4638 // and that serialisation between the main and worker thread succeeds.
4639 QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
4640 QDeclarativeComponent component(&engine, qmlFile);
4641 QObject *object = component.create();
4642 QVERIFY(object != 0);
4644 QMetaObject::invokeMethod(object, "testIntSequence");
4645 QTRY_VERIFY(object->property("finished").toBool());
4646 QVERIFY(object->property("success").toBool());
4648 QMetaObject::invokeMethod(object, "testQrealSequence");
4649 QTRY_VERIFY(object->property("finished").toBool());
4650 QVERIFY(object->property("success").toBool());
4652 QMetaObject::invokeMethod(object, "testBoolSequence");
4653 QTRY_VERIFY(object->property("finished").toBool());
4654 QVERIFY(object->property("success").toBool());
4656 QMetaObject::invokeMethod(object, "testStringSequence");
4657 QTRY_VERIFY(object->property("finished").toBool());
4658 QVERIFY(object->property("success").toBool());
4660 QMetaObject::invokeMethod(object, "testQStringSequence");
4661 QTRY_VERIFY(object->property("finished").toBool());
4662 QVERIFY(object->property("success").toBool());
4664 QMetaObject::invokeMethod(object, "testUrlSequence");
4665 QTRY_VERIFY(object->property("finished").toBool());
4666 QVERIFY(object->property("success").toBool());
4668 QMetaObject::invokeMethod(object, "testVariantSequence");
4669 QTRY_VERIFY(object->property("finished").toBool());
4670 QVERIFY(object->property("success").toBool());
4675 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4678 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
4679 QDeclarativeComponent component(&engine, qmlFile);
4680 QObject *object = component.create();
4681 QVERIFY(object != 0);
4682 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4683 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4684 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4685 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4686 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4691 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
4692 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4693 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4694 QDeclarativeComponent component(&engine, qmlFile);
4695 QObject *object = component.create();
4696 QVERIFY(object != 0);
4701 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4703 QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
4704 QDeclarativeComponent component(&engine, qmlFile);
4705 QObject *object = component.create();
4706 QVERIFY(object != 0);
4707 QMetaObject::invokeMethod(object, "testCopySequences");
4708 QCOMPARE(object->property("success").toBool(), true);
4709 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4710 QCOMPARE(object->property("success").toBool(), true);
4711 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4712 QCOMPARE(object->property("success").toBool(), true);
4716 void tst_qdeclarativeecmascript::assignSequenceTypes()
4718 // test binding array to sequence type property
4720 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
4721 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4722 QVERIFY(object != 0);
4723 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4724 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4725 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4726 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4727 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4728 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4732 // test binding literal to sequence type property
4734 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
4735 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4736 QVERIFY(object != 0);
4737 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4738 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4739 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4740 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4741 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4742 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4746 // test binding single value to sequence type property
4748 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
4749 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4750 QVERIFY(object != 0);
4751 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4752 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4753 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4754 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4758 // test assigning array to sequence type property in js function
4760 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
4761 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4762 QVERIFY(object != 0);
4763 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4764 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4765 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4766 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4767 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4768 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4772 // test assigning literal to sequence type property in js function
4774 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
4775 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4776 QVERIFY(object != 0);
4777 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4778 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4779 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4780 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4781 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4782 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4786 // test assigning single value to sequence type property in js function
4788 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
4789 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4790 QVERIFY(object != 0);
4791 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4792 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4793 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4794 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4798 // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
4800 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
4801 QObject *object = component.create();
4802 QVERIFY(object != 0);
4803 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
4804 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
4805 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
4806 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
4807 MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
4808 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
4809 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4810 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4811 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4812 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4813 QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4818 // Test that assigning a null object works
4819 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4820 void tst_qdeclarativeecmascript::nullObjectBinding()
4822 QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
4824 QObject *object = component.create();
4825 QVERIFY(object != 0);
4827 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4832 // Test that bindings don't evaluate once the engine has been destroyed
4833 void tst_qdeclarativeecmascript::deletedEngine()
4835 QDeclarativeEngine *engine = new QDeclarativeEngine;
4836 QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
4838 QObject *object = component.create();
4839 QVERIFY(object != 0);
4841 QCOMPARE(object->property("a").toInt(), 39);
4842 object->setProperty("b", QVariant(9));
4843 QCOMPARE(object->property("a").toInt(), 117);
4847 QCOMPARE(object->property("a").toInt(), 117);
4848 object->setProperty("b", QVariant(10));
4849 QCOMPARE(object->property("a").toInt(), 117);
4854 // Test the crashing part of QTBUG-9705
4855 void tst_qdeclarativeecmascript::libraryScriptAssert()
4857 QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
4859 QObject *object = component.create();
4860 QVERIFY(object != 0);
4865 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4867 QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
4869 QObject *object = component.create();
4870 QVERIFY(object != 0);
4872 QCOMPARE(object->property("test1").toInt(), 10);
4873 QCOMPARE(object->property("test2").toInt(), 11);
4875 object->setProperty("runTest", true);
4877 QCOMPARE(object->property("test1"), QVariant());
4878 QCOMPARE(object->property("test2"), QVariant());
4884 void tst_qdeclarativeecmascript::qtbug_9792()
4886 QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
4888 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4890 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4891 QVERIFY(object != 0);
4893 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4894 object->basicSignal();
4898 transientErrorsMsgCount = 0;
4899 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4901 object->basicSignal();
4903 qInstallMsgHandler(old);
4905 QCOMPARE(transientErrorsMsgCount, 0);
4910 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4911 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4913 QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
4915 QObject *o = component.create();
4918 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4919 QVERIFY(nested != 0);
4921 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4924 nested = qvariant_cast<QObject *>(o->property("object"));
4925 QVERIFY(nested == 0);
4927 // If the bug is present, the next line will crash
4931 // Test that we shut down without stupid warnings
4932 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4935 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
4937 QObject *o = component.create();
4939 transientErrorsMsgCount = 0;
4940 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4944 qInstallMsgHandler(old);
4946 QCOMPARE(transientErrorsMsgCount, 0);
4951 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
4953 QObject *o = component.create();
4955 transientErrorsMsgCount = 0;
4956 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4960 qInstallMsgHandler(old);
4962 QCOMPARE(transientErrorsMsgCount, 0);
4966 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4969 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
4971 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4974 QVERIFY(o->objectProperty() != 0);
4976 o->setProperty("runTest", true);
4978 QVERIFY(o->objectProperty() == 0);
4984 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
4986 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4989 QVERIFY(o->objectProperty() == 0);
4995 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4997 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
4999 QString url = component.url().toString();
5000 QString warning = url + ":4: Unable to assign a function to a property.";
5001 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5003 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5006 QVERIFY(!o->property("a").isValid());
5011 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
5013 QFETCH(QString, triggerProperty);
5015 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
5016 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
5018 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5020 QVERIFY(!o->property("a").isValid());
5022 o->setProperty("aNumber", QVariant(5));
5023 o->setProperty(triggerProperty.toUtf8().constData(), true);
5024 QCOMPARE(o->property("a"), QVariant(50));
5026 o->setProperty("aNumber", QVariant(10));
5027 QCOMPARE(o->property("a"), QVariant(100));
5032 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
5034 QTest::addColumn<QString>("triggerProperty");
5036 QTest::newRow("assign to property") << "assignToProperty";
5037 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
5039 QTest::newRow("assign to value type") << "assignToValueType";
5041 QTest::newRow("use 'this'") << "assignWithThis";
5042 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
5045 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
5047 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
5048 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
5050 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
5052 QVERIFY(!o->property("a").isValid());
5054 o->setProperty("assignFuncWithoutReturn", true);
5055 QVERIFY(!o->property("a").isValid());
5057 QString url = component.url().toString();
5058 QString warning = url + ":67: Unable to assign QString to int";
5059 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5060 o->setProperty("assignWrongType", true);
5062 warning = url + ":71: Unable to assign QString to int";
5063 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
5064 o->setProperty("assignWrongTypeToValueType", true);
5069 void tst_qdeclarativeecmascript::eval()
5071 QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
5073 QObject *o = component.create();
5076 QCOMPARE(o->property("test1").toBool(), true);
5077 QCOMPARE(o->property("test2").toBool(), true);
5078 QCOMPARE(o->property("test3").toBool(), true);
5079 QCOMPARE(o->property("test4").toBool(), true);
5080 QCOMPARE(o->property("test5").toBool(), true);
5085 void tst_qdeclarativeecmascript::function()
5087 QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
5089 QObject *o = component.create();
5092 QCOMPARE(o->property("test1").toBool(), true);
5093 QCOMPARE(o->property("test2").toBool(), true);
5094 QCOMPARE(o->property("test3").toBool(), true);
5099 void tst_qdeclarativeecmascript::functionException()
5101 // QTBUG-24037 - shouldn't crash.
5102 QString errstr = testFileUrl("v8functionException.qml").toString() + QLatin1String(":13: SyntaxError: Unexpected token ILLEGAL");
5103 QTest::ignoreMessage(QtWarningMsg, qPrintable(errstr));
5104 QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Exception occurred during compilation of function: dynamicSlot()");
5105 QDeclarativeComponent component(&engine, testFileUrl("v8functionException.qml"));
5106 QObject *o = component.create();
5108 QMetaObject::invokeMethod(o, "dynamicSlot");
5112 // Test the "Qt.include" method
5113 void tst_qdeclarativeecmascript::include()
5115 // Non-library relative include
5117 QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
5118 QObject *o = component.create();
5121 QCOMPARE(o->property("test0").toInt(), 99);
5122 QCOMPARE(o->property("test1").toBool(), true);
5123 QCOMPARE(o->property("test2").toBool(), true);
5124 QCOMPARE(o->property("test2_1").toBool(), true);
5125 QCOMPARE(o->property("test3").toBool(), true);
5126 QCOMPARE(o->property("test3_1").toBool(), true);
5131 // Library relative include
5133 QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
5134 QObject *o = component.create();
5137 QCOMPARE(o->property("test0").toInt(), 99);
5138 QCOMPARE(o->property("test1").toBool(), true);
5139 QCOMPARE(o->property("test2").toBool(), true);
5140 QCOMPARE(o->property("test2_1").toBool(), true);
5141 QCOMPARE(o->property("test3").toBool(), true);
5142 QCOMPARE(o->property("test3_1").toBool(), true);
5149 QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
5150 QObject *o = component.create();
5153 QCOMPARE(o->property("test1").toBool(), true);
5154 QCOMPARE(o->property("test2").toBool(), true);
5155 QCOMPARE(o->property("test3").toBool(), true);
5156 QCOMPARE(o->property("test4").toBool(), true);
5157 QCOMPARE(o->property("test5").toBool(), true);
5158 QCOMPARE(o->property("test6").toBool(), true);
5163 // Including file with ".pragma library"
5165 QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
5166 QObject *o = component.create();
5168 QCOMPARE(o->property("test1").toInt(), 100);
5175 TestHTTPServer server(8111);
5176 QVERIFY(server.isValid());
5177 server.serveDirectory(dataDirectory());
5179 QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
5180 QObject *o = component.create();
5183 QTRY_VERIFY(o->property("done").toBool() == true);
5184 QTRY_VERIFY(o->property("done2").toBool() == true);
5186 QCOMPARE(o->property("test1").toBool(), true);
5187 QCOMPARE(o->property("test2").toBool(), true);
5188 QCOMPARE(o->property("test3").toBool(), true);
5189 QCOMPARE(o->property("test4").toBool(), true);
5190 QCOMPARE(o->property("test5").toBool(), true);
5192 QCOMPARE(o->property("test6").toBool(), true);
5193 QCOMPARE(o->property("test7").toBool(), true);
5194 QCOMPARE(o->property("test8").toBool(), true);
5195 QCOMPARE(o->property("test9").toBool(), true);
5196 QCOMPARE(o->property("test10").toBool(), true);
5203 TestHTTPServer server(8111);
5204 QVERIFY(server.isValid());
5205 server.serveDirectory(dataDirectory());
5207 QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
5208 QObject *o = component.create();
5211 QTRY_VERIFY(o->property("done").toBool() == true);
5213 QCOMPARE(o->property("test1").toBool(), true);
5214 QCOMPARE(o->property("test2").toBool(), true);
5215 QCOMPARE(o->property("test3").toBool(), true);
5221 void tst_qdeclarativeecmascript::signalHandlers()
5223 QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
5224 QObject *o = component.create();
5227 QVERIFY(o->property("count").toInt() == 0);
5228 QMetaObject::invokeMethod(o, "testSignalCall");
5229 QCOMPARE(o->property("count").toInt(), 1);
5231 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5232 QCOMPARE(o->property("count").toInt(), 1);
5233 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5235 QVERIFY(o->property("funcCount").toInt() == 0);
5236 QMetaObject::invokeMethod(o, "testSignalConnection");
5237 QCOMPARE(o->property("funcCount").toInt(), 1);
5239 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5240 QCOMPARE(o->property("funcCount").toInt(), 2);
5242 QMetaObject::invokeMethod(o, "testSignalDefined");
5243 QCOMPARE(o->property("definedResult").toBool(), true);
5245 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5246 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5251 void tst_qdeclarativeecmascript::qtbug_10696()
5253 QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
5254 QObject *o = component.create();
5259 void tst_qdeclarativeecmascript::qtbug_11606()
5261 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
5262 QObject *o = component.create();
5264 QCOMPARE(o->property("test").toBool(), true);
5268 void tst_qdeclarativeecmascript::qtbug_11600()
5270 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
5271 QObject *o = component.create();
5273 QCOMPARE(o->property("test").toBool(), true);
5277 void tst_qdeclarativeecmascript::qtbug_21864()
5279 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
5280 QObject *o = component.create();
5282 QCOMPARE(o->property("test").toBool(), true);
5286 void tst_qdeclarativeecmascript::rewriteMultiLineStrings()
5290 QDeclarativeComponent component(&engine, testFileUrl("rewriteMultiLineStrings.qml"));
5291 QObject *o = component.create();
5293 QTRY_COMPARE(o->property("test").toBool(), true);
5298 QDeclarativeComponent component(&engine, testFileUrl("rewriteMultiLineStrings_crlf.1.qml"));
5299 QObject *o = component.create();
5305 void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
5308 QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
5309 QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
5310 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5311 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5312 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5313 QObject *o = component.create();
5315 QCOMPARE(o->property("test").toBool(), true);
5319 // Reading and writing non-scriptable properties should fail
5320 void tst_qdeclarativeecmascript::nonscriptable()
5322 QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
5323 QObject *o = component.create();
5325 QCOMPARE(o->property("readOk").toBool(), true);
5326 QCOMPARE(o->property("writeOk").toBool(), true);
5330 // deleteLater() should not be callable from QML
5331 void tst_qdeclarativeecmascript::deleteLater()
5333 QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
5334 QObject *o = component.create();
5336 QCOMPARE(o->property("test").toBool(), true);
5340 void tst_qdeclarativeecmascript::in()
5342 QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
5343 QObject *o = component.create();
5345 QCOMPARE(o->property("test1").toBool(), true);
5346 QCOMPARE(o->property("test2").toBool(), true);
5350 void tst_qdeclarativeecmascript::typeOf()
5352 QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
5354 // These warnings should not happen once QTBUG-21864 is fixed
5355 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5356 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5358 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5359 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5361 QObject *o = component.create();
5364 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5365 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5366 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5367 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5368 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5369 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5370 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5371 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5372 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5373 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5378 void tst_qdeclarativeecmascript::sharedAttachedObject()
5380 QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
5381 QObject *o = component.create();
5383 QCOMPARE(o->property("test1").toBool(), true);
5384 QCOMPARE(o->property("test2").toBool(), true);
5389 void tst_qdeclarativeecmascript::objectName()
5391 QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
5392 QObject *o = component.create();
5395 QCOMPARE(o->property("test1").toString(), QString("hello"));
5396 QCOMPARE(o->property("test2").toString(), QString("ell"));
5398 o->setObjectName("world");
5400 QCOMPARE(o->property("test1").toString(), QString("world"));
5401 QCOMPARE(o->property("test2").toString(), QString("orl"));
5406 void tst_qdeclarativeecmascript::writeRemovesBinding()
5408 QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
5409 QObject *o = component.create();
5412 QCOMPARE(o->property("test").toBool(), true);
5417 // Test bindings assigned to alias properties actually assign to the alias' target
5418 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5420 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
5421 QObject *o = component.create();
5424 QCOMPARE(o->property("test").toBool(), true);
5429 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5430 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5433 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
5434 QObject *o = component.create();
5437 QCOMPARE(o->property("test").toBool(), true);
5443 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
5444 QObject *o = component.create();
5447 QCOMPARE(o->property("test").toBool(), true);
5453 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
5454 QObject *o = component.create();
5457 QCOMPARE(o->property("test").toBool(), true);
5463 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5464 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5467 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
5468 QObject *o = component.create();
5471 QCOMPARE(o->property("test").toBool(), true);
5477 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
5478 QObject *o = component.create();
5481 QCOMPARE(o->property("test").toBool(), true);
5487 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
5488 QObject *o = component.create();
5491 QCOMPARE(o->property("test").toBool(), true);
5497 // Allow an alais to a composite element
5499 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5501 QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
5503 QObject *object = component.create();
5504 QVERIFY(object != 0);
5509 void tst_qdeclarativeecmascript::qtbug_20344()
5511 QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
5513 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5514 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5516 QObject *object = component.create();
5517 QVERIFY(object != 0);
5522 void tst_qdeclarativeecmascript::revisionErrors()
5525 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
5526 QString url = component.url().toString();
5528 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5529 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5530 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5532 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5533 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5534 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5535 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5536 QVERIFY(object != 0);
5540 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
5541 QString url = component.url().toString();
5543 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5544 // method2, prop2 from MyRevisionedClass not available
5545 // method4, prop4 from MyRevisionedSubclass not available
5546 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5547 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5548 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5549 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5550 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5552 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5553 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5554 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5555 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5556 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5557 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5558 QVERIFY(object != 0);
5562 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
5563 QString url = component.url().toString();
5565 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5566 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5567 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5568 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5569 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5570 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5571 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5572 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5573 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5574 QVERIFY(object != 0);
5579 void tst_qdeclarativeecmascript::revision()
5582 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
5583 QString url = component.url().toString();
5585 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5586 QVERIFY(object != 0);
5590 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
5591 QString url = component.url().toString();
5593 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5594 QVERIFY(object != 0);
5598 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
5599 QString url = component.url().toString();
5601 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5602 QVERIFY(object != 0);
5605 // Test that non-root classes can resolve revisioned methods
5607 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
5609 QObject *object = component.create();
5610 QVERIFY(object != 0);
5611 QCOMPARE(object->property("test").toReal(), 11.);
5616 void tst_qdeclarativeecmascript::realToInt()
5618 QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
5619 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5620 QVERIFY(object != 0);
5622 QMetaObject::invokeMethod(object, "test1");
5623 QCOMPARE(object->value(), int(4));
5624 QMetaObject::invokeMethod(object, "test2");
5625 QCOMPARE(object->value(), int(8));
5628 void tst_qdeclarativeecmascript::urlProperty()
5631 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
5632 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5633 QVERIFY(object != 0);
5634 object->setStringProperty("http://qt-project.org");
5635 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5636 QCOMPARE(object->intProperty(), 123);
5637 QCOMPARE(object->value(), 1);
5638 QCOMPARE(object->property("result").toBool(), true);
5642 void tst_qdeclarativeecmascript::urlPropertyWithEncoding()
5645 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.2.qml"));
5646 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5647 QVERIFY(object != 0);
5648 object->setStringProperty("http://qt-project.org");
5650 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5651 QCOMPARE(object->urlProperty(), encoded);
5652 QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
5653 QCOMPARE(object->property("result").toBool(), true);
5657 void tst_qdeclarativeecmascript::urlListPropertyWithEncoding()
5660 QDeclarativeComponent component(&engine, testFileUrl("urlListProperty.qml"));
5661 QObject *object = component.create();
5662 QVERIFY(object != 0);
5663 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
5664 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
5665 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
5666 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
5667 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
5669 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5670 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
5671 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
5672 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5673 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5678 void tst_qdeclarativeecmascript::dynamicString()
5680 QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
5681 QObject *object = component.create();
5682 QVERIFY(object != 0);
5683 QCOMPARE(object->property("stringProperty").toString(),
5684 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5687 void tst_qdeclarativeecmascript::automaticSemicolon()
5689 QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
5690 QObject *object = component.create();
5691 QVERIFY(object != 0);
5694 void tst_qdeclarativeecmascript::unaryExpression()
5696 QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
5697 QObject *object = component.create();
5698 QVERIFY(object != 0);
5701 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5702 void tst_qdeclarativeecmascript::doubleEvaluate()
5704 QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
5705 QObject *object = component.create();
5706 QVERIFY(object != 0);
5707 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5709 QCOMPARE(wc->count(), 1);
5711 wc->setProperty("x", 9);
5713 QCOMPARE(wc->count(), 2);
5718 static QStringList messages;
5719 static void captureMsgHandler(QtMsgType, const char *msg)
5721 messages.append(QLatin1String(msg));
5724 void tst_qdeclarativeecmascript::nonNotifyable()
5726 QV4Compiler::enableV4(false);
5727 QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
5728 QV4Compiler::enableV4(true);
5730 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5732 QObject *object = component.create();
5733 qInstallMsgHandler(old);
5735 QVERIFY(object != 0);
5737 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5738 component.url().toString() +
5739 QLatin1String(":5 depends on non-NOTIFYable properties:");
5740 QString expected2 = QLatin1String(" ") +
5741 QLatin1String(object->metaObject()->className()) +
5742 QLatin1String("::value");
5744 QCOMPARE(messages.length(), 2);
5745 QCOMPARE(messages.at(0), expected1);
5746 QCOMPARE(messages.at(1), expected2);
5751 void tst_qdeclarativeecmascript::forInLoop()
5753 QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
5754 QObject *object = component.create();
5755 QVERIFY(object != 0);
5757 QMetaObject::invokeMethod(object, "listProperty");
5759 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5760 QCOMPARE(r.size(), 3);
5761 QCOMPARE(r[0],QLatin1String("0=obj1"));
5762 QCOMPARE(r[1],QLatin1String("1=obj2"));
5763 QCOMPARE(r[2],QLatin1String("2=obj3"));
5765 //TODO: should test for in loop for other objects (such as QObjects) as well.
5770 // An object the binding depends on is deleted while the binding is still running
5771 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5773 QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
5774 QObject *object = component.create();
5775 QVERIFY(object != 0);
5779 void tst_qdeclarativeecmascript::qtbug_22679()
5782 object.setStringProperty(QLatin1String("Please work correctly"));
5783 engine.rootContext()->setContextProperty("contextProp", &object);
5785 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
5786 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5787 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5789 QObject *o = component.create();
5791 QCOMPARE(warningsSpy.count(), 0);
5795 void tst_qdeclarativeecmascript::qtbug_22843_data()
5797 QTest::addColumn<bool>("library");
5799 QTest::newRow("without .pragma library") << false;
5800 QTest::newRow("with .pragma library") << true;
5803 void tst_qdeclarativeecmascript::qtbug_22843()
5805 QFETCH(bool, library);
5807 QString fileName("qtbug_22843");
5809 fileName += QLatin1String(".library");
5810 fileName += QLatin1String(".qml");
5812 QDeclarativeComponent component(&engine, testFileUrl(fileName));
5813 QString url = component.url().toString();
5814 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5815 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5817 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5818 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5819 for (int x = 0; x < 3; ++x) {
5820 warningsSpy.clear();
5821 // For libraries, only the first import attempt should produce a
5822 // SyntaxError warning; subsequent component creation should not
5823 // attempt to reload the script.
5824 bool expectSyntaxError = !library || (x == 0);
5825 if (expectSyntaxError)
5826 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5827 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5828 QObject *object = component.create();
5829 QVERIFY(object != 0);
5830 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5836 void tst_qdeclarativeecmascript::switchStatement()
5839 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
5840 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5841 QVERIFY(object != 0);
5843 // `object->value()' is the number of executed statements
5845 object->setStringProperty("A");
5846 QCOMPARE(object->value(), 5);
5848 object->setStringProperty("S");
5849 QCOMPARE(object->value(), 3);
5851 object->setStringProperty("D");
5852 QCOMPARE(object->value(), 3);
5854 object->setStringProperty("F");
5855 QCOMPARE(object->value(), 4);
5857 object->setStringProperty("something else");
5858 QCOMPARE(object->value(), 1);
5862 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
5863 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5864 QVERIFY(object != 0);
5866 // `object->value()' is the number of executed statements
5868 object->setStringProperty("A");
5869 QCOMPARE(object->value(), 5);
5871 object->setStringProperty("S");
5872 QCOMPARE(object->value(), 3);
5874 object->setStringProperty("D");
5875 QCOMPARE(object->value(), 3);
5877 object->setStringProperty("F");
5878 QCOMPARE(object->value(), 3);
5880 object->setStringProperty("something else");
5881 QCOMPARE(object->value(), 4);
5885 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
5886 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5887 QVERIFY(object != 0);
5889 // `object->value()' is the number of executed statements
5891 object->setStringProperty("A");
5892 QCOMPARE(object->value(), 5);
5894 object->setStringProperty("S");
5895 QCOMPARE(object->value(), 3);
5897 object->setStringProperty("D");
5898 QCOMPARE(object->value(), 3);
5900 object->setStringProperty("F");
5901 QCOMPARE(object->value(), 3);
5903 object->setStringProperty("something else");
5904 QCOMPARE(object->value(), 6);
5908 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
5910 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5911 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5913 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5914 QVERIFY(object != 0);
5916 // `object->value()' is the number of executed statements
5918 object->setStringProperty("A");
5919 QCOMPARE(object->value(), 5);
5921 object->setStringProperty("S");
5922 QCOMPARE(object->value(), 3);
5924 object->setStringProperty("D");
5925 QCOMPARE(object->value(), 3);
5927 object->setStringProperty("F");
5928 QCOMPARE(object->value(), 3);
5930 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5932 object->setStringProperty("something else");
5936 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
5937 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5938 QVERIFY(object != 0);
5940 // `object->value()' is the number of executed statements
5942 object->setStringProperty("A");
5943 QCOMPARE(object->value(), 1);
5945 object->setStringProperty("S");
5946 QCOMPARE(object->value(), 1);
5948 object->setStringProperty("D");
5949 QCOMPARE(object->value(), 1);
5951 object->setStringProperty("F");
5952 QCOMPARE(object->value(), 1);
5954 object->setStringProperty("something else");
5955 QCOMPARE(object->value(), 1);
5959 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
5960 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5961 QVERIFY(object != 0);
5963 // `object->value()' is the number of executed statements
5965 object->setStringProperty("A");
5966 QCOMPARE(object->value(), 123);
5968 object->setStringProperty("S");
5969 QCOMPARE(object->value(), 123);
5971 object->setStringProperty("D");
5972 QCOMPARE(object->value(), 321);
5974 object->setStringProperty("F");
5975 QCOMPARE(object->value(), 321);
5977 object->setStringProperty("something else");
5978 QCOMPARE(object->value(), 0);
5982 void tst_qdeclarativeecmascript::withStatement()
5985 QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
5986 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5987 QVERIFY(object != 0);
5989 QCOMPARE(object->value(), 123);
5993 void tst_qdeclarativeecmascript::tryStatement()
5996 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
5997 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5998 QVERIFY(object != 0);
6000 QCOMPARE(object->value(), 123);
6004 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
6005 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
6006 QVERIFY(object != 0);
6008 QCOMPARE(object->value(), 321);
6012 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
6013 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
6014 QVERIFY(object != 0);
6016 QCOMPARE(object->value(), 1);
6020 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
6021 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
6022 QVERIFY(object != 0);
6024 QCOMPARE(object->value(), 1);
6028 class CppInvokableWithQObjectDerived : public QObject
6032 CppInvokableWithQObjectDerived() {}
6033 ~CppInvokableWithQObjectDerived() {}
6035 Q_INVOKABLE MyQmlObject *createMyQmlObject(QString data)
6037 MyQmlObject *obj = new MyQmlObject();
6038 obj->setStringProperty(data);
6042 Q_INVOKABLE QString getStringProperty(MyQmlObject *obj)
6044 return obj->stringProperty();
6048 void tst_qdeclarativeecmascript::invokableWithQObjectDerived()
6050 CppInvokableWithQObjectDerived invokable;
6053 QDeclarativeEngine engine;
6054 engine.rootContext()->setContextProperty("invokable", &invokable);
6056 QDeclarativeComponent component(&engine, testFileUrl("qobjectDerivedArgument.qml"));
6058 QObject *object = component.create();
6060 QVERIFY(object != 0);
6061 QVERIFY(object->property("result").value<bool>() == true);
6067 QTEST_MAIN(tst_qdeclarativeecmascript)
6069 #include "tst_qdeclarativeecmascript.moc"