1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include <private/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 transientErrors();
117 void shutdownErrors();
118 void compositePropertyType();
120 void undefinedResetsProperty();
121 void listToVariant();
122 void listAssignment();
123 void multiEngineObject();
124 void deletedObject();
125 void attachedPropertyScope();
126 void scriptConnect();
127 void scriptDisconnect();
129 void cppOwnershipReturnValue();
130 void ownershipCustomReturnValue();
131 void qlistqobjectMethods();
132 void strictlyEquals();
134 void numberAssignment();
135 void propertySplicing();
136 void signalWithUnknownTypes();
137 void signalWithJSValueInVariant_data();
138 void signalWithJSValueInVariant();
139 void signalWithJSValueInVariant_twoEngines_data();
140 void signalWithJSValueInVariant_twoEngines();
141 void signalWithQJSValue_data();
142 void signalWithQJSValue();
143 void moduleApi_data();
145 void importScripts_data();
146 void importScripts();
147 void scarceResources();
148 void scarceResources_data();
149 void scarceResources_other();
150 void propertyChangeSlots();
151 void propertyVar_data();
153 void propertyVarCpp();
154 void propertyVarOwnership();
155 void propertyVarImplicitOwnership();
156 void propertyVarReparent();
157 void propertyVarReparentNullContext();
158 void propertyVarCircular();
159 void propertyVarCircular2();
160 void propertyVarInheritance();
161 void propertyVarInheritance2();
162 void elementAssign();
163 void objectPassThroughSignals();
164 void objectConversion();
165 void booleanConversion();
166 void handleReferenceManagement();
168 void readonlyDeclaration();
169 void sequenceConversionRead();
170 void sequenceConversionWrite();
171 void sequenceConversionArray();
172 void sequenceConversionThreads();
173 void sequenceConversionBindings();
174 void sequenceConversionCopy();
175 void assignSequenceTypes();
181 void dynamicCreationCrash();
182 void dynamicCreationOwnership();
184 void nullObjectBinding();
185 void deletedEngine();
186 void libraryScriptAssert();
187 void variantsAssignedUndefined();
189 void qtcreatorbug_1289();
190 void noSpuriousWarningsAtShutdown();
191 void canAssignNullToQObject();
192 void functionAssignment_fromBinding();
193 void functionAssignment_fromJS();
194 void functionAssignment_fromJS_data();
195 void functionAssignmentfromJS_invalid();
202 void qobjectConnectionListExceptionHandling();
203 void nonscriptable();
207 void sharedAttachedObject();
209 void writeRemovesBinding();
210 void aliasBindingsAssignCorrectly();
211 void aliasBindingsOverrideTarget();
212 void aliasWritesOverrideBindings();
213 void aliasToCompositeElement();
216 void urlPropertyWithEncoding();
217 void urlListPropertyWithEncoding();
218 void dynamicString();
220 void signalHandlers();
221 void doubleEvaluate();
223 void nonNotifyable();
224 void deleteWhileBindingRunning();
225 void callQtInvokables();
226 void invokableObjectArg();
227 void invokableObjectRet();
230 void qtbug_22843_data();
232 void revisionErrors();
235 void automaticSemicolon();
236 void unaryExpression();
237 void switchStatement();
238 void withStatement();
242 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
243 QDeclarativeEngine engine;
246 void tst_qdeclarativeecmascript::initTestCase()
248 QDeclarativeDataTest::initTestCase();
252 void tst_qdeclarativeecmascript::assignBasicTypes()
255 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
256 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
257 QVERIFY(object != 0);
258 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
259 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
260 QCOMPARE(object->stringProperty(), QString("Hello World!"));
261 QCOMPARE(object->uintProperty(), uint(10));
262 QCOMPARE(object->intProperty(), -19);
263 QCOMPARE((float)object->realProperty(), float(23.2));
264 QCOMPARE((float)object->doubleProperty(), float(-19.75));
265 QCOMPARE((float)object->floatProperty(), float(8.5));
266 QCOMPARE(object->colorProperty(), QColor("red"));
267 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
268 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
269 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
270 QCOMPARE(object->pointProperty(), QPoint(99,13));
271 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
272 QCOMPARE(object->sizeProperty(), QSize(99, 13));
273 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
274 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
275 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
276 QCOMPARE(object->boolProperty(), true);
277 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
278 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
279 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
283 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
284 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
285 QVERIFY(object != 0);
286 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
287 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
288 QCOMPARE(object->stringProperty(), QString("Hello World!"));
289 QCOMPARE(object->uintProperty(), uint(10));
290 QCOMPARE(object->intProperty(), -19);
291 QCOMPARE((float)object->realProperty(), float(23.2));
292 QCOMPARE((float)object->doubleProperty(), float(-19.75));
293 QCOMPARE((float)object->floatProperty(), float(8.5));
294 QCOMPARE(object->colorProperty(), QColor("red"));
295 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
296 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
297 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
298 QCOMPARE(object->pointProperty(), QPoint(99,13));
299 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
300 QCOMPARE(object->sizeProperty(), QSize(99, 13));
301 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
302 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
303 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
304 QCOMPARE(object->boolProperty(), true);
305 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
306 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
307 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
312 void tst_qdeclarativeecmascript::idShortcutInvalidates()
315 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
316 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
317 QVERIFY(object != 0);
318 QVERIFY(object->objectProperty() != 0);
319 delete object->objectProperty();
320 QVERIFY(object->objectProperty() == 0);
325 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
326 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
327 QVERIFY(object != 0);
328 QVERIFY(object->objectProperty() != 0);
329 delete object->objectProperty();
330 QVERIFY(object->objectProperty() == 0);
335 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
338 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
339 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
340 QVERIFY(object != 0);
341 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
345 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
346 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
347 QVERIFY(object != 0);
348 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
353 void tst_qdeclarativeecmascript::signalAssignment()
356 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
357 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
358 QVERIFY(object != 0);
359 QCOMPARE(object->string(), QString());
360 emit object->basicSignal();
361 QCOMPARE(object->string(), QString("pass"));
366 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
367 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
368 QVERIFY(object != 0);
369 QCOMPARE(object->string(), QString());
370 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
371 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
376 void tst_qdeclarativeecmascript::methods()
379 QDeclarativeComponent component(&engine, testFileUrl("methods.1.qml"));
380 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
381 QVERIFY(object != 0);
382 QCOMPARE(object->methodCalled(), false);
383 QCOMPARE(object->methodIntCalled(), false);
384 emit object->basicSignal();
385 QCOMPARE(object->methodCalled(), true);
386 QCOMPARE(object->methodIntCalled(), false);
391 QDeclarativeComponent component(&engine, testFileUrl("methods.2.qml"));
392 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
393 QVERIFY(object != 0);
394 QCOMPARE(object->methodCalled(), false);
395 QCOMPARE(object->methodIntCalled(), false);
396 emit object->basicSignal();
397 QCOMPARE(object->methodCalled(), false);
398 QCOMPARE(object->methodIntCalled(), true);
403 QDeclarativeComponent component(&engine, testFileUrl("methods.3.qml"));
404 QObject *object = component.create();
405 QVERIFY(object != 0);
406 QCOMPARE(object->property("test").toInt(), 19);
411 QDeclarativeComponent component(&engine, testFileUrl("methods.4.qml"));
412 QObject *object = component.create();
413 QVERIFY(object != 0);
414 QCOMPARE(object->property("test").toInt(), 19);
415 QCOMPARE(object->property("test2").toInt(), 17);
416 QCOMPARE(object->property("test3").toInt(), 16);
421 QDeclarativeComponent component(&engine, testFileUrl("methods.5.qml"));
422 QObject *object = component.create();
423 QVERIFY(object != 0);
424 QCOMPARE(object->property("test").toInt(), 9);
429 void tst_qdeclarativeecmascript::bindingLoop()
431 QDeclarativeComponent component(&engine, testFileUrl("bindingLoop.qml"));
432 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
433 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
434 QObject *object = component.create();
435 QVERIFY(object != 0);
439 void tst_qdeclarativeecmascript::basicExpressions_data()
441 QTest::addColumn<QString>("expression");
442 QTest::addColumn<QVariant>("result");
443 QTest::addColumn<bool>("nest");
445 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
446 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
447 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
448 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
449 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
450 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
451 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
452 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
453 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
454 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
455 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
456 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
457 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
458 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
459 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
460 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
461 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
462 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
463 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
466 void tst_qdeclarativeecmascript::basicExpressions()
468 QFETCH(QString, expression);
469 QFETCH(QVariant, result);
475 MyDefaultObject1 default1;
476 MyDefaultObject3 default3;
477 object1.setStringProperty("Object1");
478 object2.setStringProperty("Object2");
479 object3.setStringProperty("Object3");
481 QDeclarativeContext context(engine.rootContext());
482 QDeclarativeContext nestedContext(&context);
484 context.setContextObject(&default1);
485 context.setContextProperty("a", QVariant(1944));
486 context.setContextProperty("b", QVariant("Milk"));
487 context.setContextProperty("object", &object1);
488 context.setContextProperty("objectOverride", &object2);
489 nestedContext.setContextObject(&default3);
490 nestedContext.setContextProperty("b", QVariant("Cow"));
491 nestedContext.setContextProperty("objectOverride", &object3);
492 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
494 MyExpression expr(nest?&nestedContext:&context, expression);
495 QCOMPARE(expr.evaluate(), result);
498 void tst_qdeclarativeecmascript::arrayExpressions()
504 QDeclarativeContext context(engine.rootContext());
505 context.setContextProperty("a", &obj1);
506 context.setContextProperty("b", &obj2);
507 context.setContextProperty("c", &obj3);
509 MyExpression expr(&context, "[a, b, c, 10]");
510 QVariant result = expr.evaluate();
511 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
512 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
513 QCOMPARE(list.count(), 4);
514 QCOMPARE(list.at(0), &obj1);
515 QCOMPARE(list.at(1), &obj2);
516 QCOMPARE(list.at(2), &obj3);
517 QCOMPARE(list.at(3), (QObject *)0);
520 // Tests that modifying a context property will reevaluate expressions
521 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
523 QDeclarativeContext context(engine.rootContext());
526 MyQmlObject *object3 = new MyQmlObject;
528 object1.setStringProperty("Hello");
529 object2.setStringProperty("World");
531 context.setContextProperty("testProp", QVariant(1));
532 context.setContextProperty("testObj", &object1);
533 context.setContextProperty("testObj2", object3);
536 MyExpression expr(&context, "testProp + 1");
537 QCOMPARE(expr.changed, false);
538 QCOMPARE(expr.evaluate(), QVariant(2));
540 context.setContextProperty("testProp", QVariant(2));
541 QCOMPARE(expr.changed, true);
542 QCOMPARE(expr.evaluate(), QVariant(3));
546 MyExpression expr(&context, "testProp + testProp + testProp");
547 QCOMPARE(expr.changed, false);
548 QCOMPARE(expr.evaluate(), QVariant(6));
550 context.setContextProperty("testProp", QVariant(4));
551 QCOMPARE(expr.changed, true);
552 QCOMPARE(expr.evaluate(), QVariant(12));
556 MyExpression expr(&context, "testObj.stringProperty");
557 QCOMPARE(expr.changed, false);
558 QCOMPARE(expr.evaluate(), QVariant("Hello"));
560 context.setContextProperty("testObj", &object2);
561 QCOMPARE(expr.changed, true);
562 QCOMPARE(expr.evaluate(), QVariant("World"));
566 MyExpression expr(&context, "testObj.stringProperty /**/");
567 QCOMPARE(expr.changed, false);
568 QCOMPARE(expr.evaluate(), QVariant("World"));
570 context.setContextProperty("testObj", &object1);
571 QCOMPARE(expr.changed, true);
572 QCOMPARE(expr.evaluate(), QVariant("Hello"));
576 MyExpression expr(&context, "testObj2");
577 QCOMPARE(expr.changed, false);
578 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
584 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
586 QDeclarativeContext context(engine.rootContext());
590 context.setContextProperty("testObj", &object1);
592 object1.setStringProperty(QLatin1String("Hello"));
593 object2.setStringProperty(QLatin1String("Dog"));
594 object3.setStringProperty(QLatin1String("Cat"));
597 MyExpression expr(&context, "testObj.stringProperty");
598 QCOMPARE(expr.changed, false);
599 QCOMPARE(expr.evaluate(), QVariant("Hello"));
601 object1.setStringProperty(QLatin1String("World"));
602 QCOMPARE(expr.changed, true);
603 QCOMPARE(expr.evaluate(), QVariant("World"));
607 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
608 QCOMPARE(expr.changed, false);
609 QCOMPARE(expr.evaluate(), QVariant());
611 object1.setObjectProperty(&object2);
612 QCOMPARE(expr.changed, true);
613 expr.changed = false;
614 QCOMPARE(expr.evaluate(), QVariant("Dog"));
616 object1.setObjectProperty(&object3);
617 QCOMPARE(expr.changed, true);
618 expr.changed = false;
619 QCOMPARE(expr.evaluate(), QVariant("Cat"));
621 object1.setObjectProperty(0);
622 QCOMPARE(expr.changed, true);
623 expr.changed = false;
624 QCOMPARE(expr.evaluate(), QVariant());
626 object1.setObjectProperty(&object3);
627 QCOMPARE(expr.changed, true);
628 expr.changed = false;
629 QCOMPARE(expr.evaluate(), QVariant("Cat"));
631 object3.setStringProperty("Donkey");
632 QCOMPARE(expr.changed, true);
633 expr.changed = false;
634 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
638 void tst_qdeclarativeecmascript::deferredProperties()
640 QDeclarativeComponent component(&engine, testFileUrl("deferredProperties.qml"));
641 MyDeferredObject *object =
642 qobject_cast<MyDeferredObject *>(component.create());
643 QVERIFY(object != 0);
644 QCOMPARE(object->value(), 0);
645 QVERIFY(object->objectProperty() == 0);
646 QVERIFY(object->objectProperty2() != 0);
647 qmlExecuteDeferred(object);
648 QCOMPARE(object->value(), 10);
649 QVERIFY(object->objectProperty() != 0);
650 MyQmlObject *qmlObject =
651 qobject_cast<MyQmlObject *>(object->objectProperty());
652 QVERIFY(qmlObject != 0);
653 QCOMPARE(qmlObject->value(), 10);
654 object->setValue(19);
655 QCOMPARE(qmlObject->value(), 19);
660 // Check errors on deferred properties are correctly emitted
661 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
663 QDeclarativeComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
664 MyDeferredObject *object =
665 qobject_cast<MyDeferredObject *>(component.create());
666 QVERIFY(object != 0);
667 QCOMPARE(object->value(), 0);
668 QVERIFY(object->objectProperty() == 0);
669 QVERIFY(object->objectProperty2() == 0);
671 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
672 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
674 qmlExecuteDeferred(object);
679 void tst_qdeclarativeecmascript::extensionObjects()
681 QDeclarativeComponent component(&engine, testFileUrl("extensionObjects.qml"));
682 MyExtendedObject *object =
683 qobject_cast<MyExtendedObject *>(component.create());
684 QVERIFY(object != 0);
685 QCOMPARE(object->baseProperty(), 13);
686 QCOMPARE(object->coreProperty(), 9);
687 object->setProperty("extendedProperty", QVariant(11));
688 object->setProperty("baseExtendedProperty", QVariant(92));
689 QCOMPARE(object->coreProperty(), 11);
690 QCOMPARE(object->baseProperty(), 92);
692 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
694 QCOMPARE(nested->baseProperty(), 13);
695 QCOMPARE(nested->coreProperty(), 9);
696 nested->setProperty("extendedProperty", QVariant(11));
697 nested->setProperty("baseExtendedProperty", QVariant(92));
698 QCOMPARE(nested->coreProperty(), 11);
699 QCOMPARE(nested->baseProperty(), 92);
704 void tst_qdeclarativeecmascript::overrideExtensionProperties()
706 QDeclarativeComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
707 OverrideDefaultPropertyObject *object =
708 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
709 QVERIFY(object != 0);
710 QVERIFY(object->secondProperty() != 0);
711 QVERIFY(object->firstProperty() == 0);
716 void tst_qdeclarativeecmascript::attachedProperties()
719 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.qml"));
720 QObject *object = component.create();
721 QVERIFY(object != 0);
722 QCOMPARE(object->property("a").toInt(), 19);
723 QCOMPARE(object->property("b").toInt(), 19);
724 QCOMPARE(object->property("c").toInt(), 19);
725 QCOMPARE(object->property("d").toInt(), 19);
730 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
731 QObject *object = component.create();
732 QVERIFY(object != 0);
733 QCOMPARE(object->property("a").toInt(), 26);
734 QCOMPARE(object->property("b").toInt(), 26);
735 QCOMPARE(object->property("c").toInt(), 26);
736 QCOMPARE(object->property("d").toInt(), 26);
742 QDeclarativeComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
743 QObject *object = component.create();
744 QVERIFY(object != 0);
746 QMetaObject::invokeMethod(object, "writeValue2");
748 MyQmlAttachedObject *attached =
749 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
750 QVERIFY(attached != 0);
752 QCOMPARE(attached->value2(), 9);
757 void tst_qdeclarativeecmascript::enums()
761 QDeclarativeComponent component(&engine, testFileUrl("enums.1.qml"));
762 QObject *object = component.create();
763 QVERIFY(object != 0);
765 QCOMPARE(object->property("a").toInt(), 0);
766 QCOMPARE(object->property("b").toInt(), 1);
767 QCOMPARE(object->property("c").toInt(), 2);
768 QCOMPARE(object->property("d").toInt(), 3);
769 QCOMPARE(object->property("e").toInt(), 0);
770 QCOMPARE(object->property("f").toInt(), 1);
771 QCOMPARE(object->property("g").toInt(), 2);
772 QCOMPARE(object->property("h").toInt(), 3);
773 QCOMPARE(object->property("i").toInt(), 19);
774 QCOMPARE(object->property("j").toInt(), 19);
778 // Non-existent enums
780 QDeclarativeComponent component(&engine, testFileUrl("enums.2.qml"));
782 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
783 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
784 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
785 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
787 QObject *object = component.create();
788 QVERIFY(object != 0);
789 QCOMPARE(object->property("a").toInt(), 0);
790 QCOMPARE(object->property("b").toInt(), 0);
796 void tst_qdeclarativeecmascript::valueTypeFunctions()
798 QDeclarativeComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
799 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
801 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
802 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
808 Tests that writing a constant to a property with a binding on it disables the
811 void tst_qdeclarativeecmascript::constantsOverrideBindings()
815 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
816 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
817 QVERIFY(object != 0);
819 QCOMPARE(object->property("c2").toInt(), 0);
820 object->setProperty("c1", QVariant(9));
821 QCOMPARE(object->property("c2").toInt(), 9);
823 emit object->basicSignal();
825 QCOMPARE(object->property("c2").toInt(), 13);
826 object->setProperty("c1", QVariant(8));
827 QCOMPARE(object->property("c2").toInt(), 13);
832 // During construction
834 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
835 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
836 QVERIFY(object != 0);
838 QCOMPARE(object->property("c1").toInt(), 0);
839 QCOMPARE(object->property("c2").toInt(), 10);
840 object->setProperty("c1", QVariant(9));
841 QCOMPARE(object->property("c1").toInt(), 9);
842 QCOMPARE(object->property("c2").toInt(), 10);
850 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.3.qml"));
851 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
852 QVERIFY(object != 0);
854 QCOMPARE(object->property("c2").toInt(), 0);
855 object->setProperty("c1", QVariant(9));
856 QCOMPARE(object->property("c2").toInt(), 9);
858 object->setProperty("c2", QVariant(13));
859 QCOMPARE(object->property("c2").toInt(), 13);
860 object->setProperty("c1", QVariant(7));
861 QCOMPARE(object->property("c1").toInt(), 7);
862 QCOMPARE(object->property("c2").toInt(), 13);
870 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
871 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
872 QVERIFY(object != 0);
874 QCOMPARE(object->property("c1").toInt(), 0);
875 QCOMPARE(object->property("c3").toInt(), 10);
876 object->setProperty("c1", QVariant(9));
877 QCOMPARE(object->property("c1").toInt(), 9);
878 QCOMPARE(object->property("c3").toInt(), 10);
885 Tests that assigning a binding to a property that already has a binding causes
886 the original binding to be disabled.
888 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
890 QDeclarativeComponent component(&engine,
891 testFileUrl("outerBindingOverridesInnerBinding.qml"));
892 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
893 QVERIFY(object != 0);
895 QCOMPARE(object->property("c1").toInt(), 0);
896 QCOMPARE(object->property("c2").toInt(), 0);
897 QCOMPARE(object->property("c3").toInt(), 0);
899 object->setProperty("c1", QVariant(9));
900 QCOMPARE(object->property("c1").toInt(), 9);
901 QCOMPARE(object->property("c2").toInt(), 0);
902 QCOMPARE(object->property("c3").toInt(), 0);
904 object->setProperty("c3", QVariant(8));
905 QCOMPARE(object->property("c1").toInt(), 9);
906 QCOMPARE(object->property("c2").toInt(), 8);
907 QCOMPARE(object->property("c3").toInt(), 8);
913 Access a non-existent attached object.
915 Tests for a regression where this used to crash.
917 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
919 QDeclarativeComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
921 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
922 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
924 QObject *object = component.create();
925 QVERIFY(object != 0);
930 void tst_qdeclarativeecmascript::scope()
933 QDeclarativeComponent component(&engine, testFileUrl("scope.qml"));
934 QObject *object = component.create();
935 QVERIFY(object != 0);
937 QCOMPARE(object->property("test1").toInt(), 1);
938 QCOMPARE(object->property("test2").toInt(), 2);
939 QCOMPARE(object->property("test3").toString(), QString("1Test"));
940 QCOMPARE(object->property("test4").toString(), QString("2Test"));
941 QCOMPARE(object->property("test5").toInt(), 1);
942 QCOMPARE(object->property("test6").toInt(), 1);
943 QCOMPARE(object->property("test7").toInt(), 2);
944 QCOMPARE(object->property("test8").toInt(), 2);
945 QCOMPARE(object->property("test9").toInt(), 1);
946 QCOMPARE(object->property("test10").toInt(), 3);
952 QDeclarativeComponent component(&engine, testFileUrl("scope.2.qml"));
953 QObject *object = component.create();
954 QVERIFY(object != 0);
956 QCOMPARE(object->property("test1").toInt(), 19);
957 QCOMPARE(object->property("test2").toInt(), 19);
958 QCOMPARE(object->property("test3").toInt(), 14);
959 QCOMPARE(object->property("test4").toInt(), 14);
960 QCOMPARE(object->property("test5").toInt(), 24);
961 QCOMPARE(object->property("test6").toInt(), 24);
967 QDeclarativeComponent component(&engine, testFileUrl("scope.3.qml"));
968 QObject *object = component.create();
969 QVERIFY(object != 0);
971 QCOMPARE(object->property("test1").toBool(), true);
972 QCOMPARE(object->property("test2").toBool(), true);
973 QCOMPARE(object->property("test3").toBool(), true);
978 // Signal argument scope
980 QDeclarativeComponent component(&engine, testFileUrl("scope.4.qml"));
981 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
982 QVERIFY(object != 0);
984 QCOMPARE(object->property("test").toInt(), 0);
985 QCOMPARE(object->property("test2").toString(), QString());
987 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
989 QCOMPARE(object->property("test").toInt(), 13);
990 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
996 QDeclarativeComponent component(&engine, testFileUrl("scope.5.qml"));
997 QObject *object = component.create();
998 QVERIFY(object != 0);
1000 QCOMPARE(object->property("test1").toBool(), true);
1001 QCOMPARE(object->property("test2").toBool(), true);
1007 QDeclarativeComponent component(&engine, testFileUrl("scope.6.qml"));
1008 QObject *object = component.create();
1009 QVERIFY(object != 0);
1011 QCOMPARE(object->property("test").toBool(), true);
1017 // In 4.7, non-library javascript files that had no imports shared the imports of their
1018 // importing context
1019 void tst_qdeclarativeecmascript::importScope()
1021 QDeclarativeComponent component(&engine, testFileUrl("importScope.qml"));
1022 QObject *o = component.create();
1025 QCOMPARE(o->property("test").toInt(), 240);
1031 Tests that "any" type passes through a synthesized signal parameter. This
1032 is essentially a test of QDeclarativeMetaType::copy()
1034 void tst_qdeclarativeecmascript::signalParameterTypes()
1036 QDeclarativeComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
1037 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1038 QVERIFY(object != 0);
1040 emit object->basicSignal();
1042 QCOMPARE(object->property("intProperty").toInt(), 10);
1043 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1044 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1045 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1046 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1047 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1053 Test that two JS objects for the same QObject compare as equal.
1055 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1057 QDeclarativeComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
1058 QObject *object = component.create();
1059 QVERIFY(object != 0);
1061 QCOMPARE(object->property("test1").toBool(), true);
1062 QCOMPARE(object->property("test2").toBool(), true);
1063 QCOMPARE(object->property("test3").toBool(), true);
1064 QCOMPARE(object->property("test4").toBool(), true);
1065 QCOMPARE(object->property("test5").toBool(), true);
1071 Confirm bindings and alias properties can coexist.
1073 Tests for a regression where the binding would not reevaluate.
1075 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1077 QDeclarativeComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
1078 QObject *object = component.create();
1079 QVERIFY(object != 0);
1081 QCOMPARE(object->property("c2").toInt(), 3);
1082 QCOMPARE(object->property("c3").toInt(), 3);
1084 object->setProperty("c2", QVariant(19));
1086 QCOMPARE(object->property("c2").toInt(), 19);
1087 QCOMPARE(object->property("c3").toInt(), 19);
1093 Ensure that we can write undefined value to an alias property,
1094 and that the aliased property is reset correctly if possible.
1096 void tst_qdeclarativeecmascript::aliasPropertyReset()
1098 QObject *object = 0;
1100 // test that a manual write (of undefined) to a resettable aliased property succeeds
1101 QDeclarativeComponent c1(&engine, testFileUrl("aliasreset/aliasPropertyReset.1.qml"));
1102 object = c1.create();
1103 QVERIFY(object != 0);
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1105 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1106 QMetaObject::invokeMethod(object, "resetAliased");
1107 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1108 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1111 // test that a manual write (of undefined) to a resettable alias property succeeds
1112 QDeclarativeComponent c2(&engine, testFileUrl("aliasreset/aliasPropertyReset.2.qml"));
1113 object = c2.create();
1114 QVERIFY(object != 0);
1115 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1116 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1117 QMetaObject::invokeMethod(object, "resetAlias");
1118 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1119 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1122 // test that an alias to a bound property works correctly
1123 QDeclarativeComponent c3(&engine, testFileUrl("aliasreset/aliasPropertyReset.3.qml"));
1124 object = c3.create();
1125 QVERIFY(object != 0);
1126 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1127 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1128 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1129 QMetaObject::invokeMethod(object, "resetAlias");
1130 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1131 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1132 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1135 // test that a manual write (of undefined) to a resettable alias property
1136 // whose aliased property's object has been deleted, does not crash.
1137 QDeclarativeComponent c4(&engine, testFileUrl("aliasreset/aliasPropertyReset.4.qml"));
1138 object = c4.create();
1139 QVERIFY(object != 0);
1140 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1141 QObject *loader = object->findChild<QObject*>("loader");
1142 QVERIFY(loader != 0);
1144 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1145 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1146 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1147 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1148 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1151 // test that binding an alias property to an undefined value works correctly
1152 QDeclarativeComponent c5(&engine, testFileUrl("aliasreset/aliasPropertyReset.5.qml"));
1153 object = c5.create();
1154 QVERIFY(object != 0);
1155 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1158 // test that a manual write (of undefined) to a non-resettable property fails properly
1159 QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
1160 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1161 QDeclarativeComponent e1(&engine, url);
1162 object = e1.create();
1163 QVERIFY(object != 0);
1164 QCOMPARE(object->property("intAlias").value<int>(), 12);
1165 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1166 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1167 QMetaObject::invokeMethod(object, "resetAlias");
1168 QCOMPARE(object->property("intAlias").value<int>(), 12);
1169 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1173 void tst_qdeclarativeecmascript::dynamicCreation_data()
1175 QTest::addColumn<QString>("method");
1176 QTest::addColumn<QString>("createdName");
1178 QTest::newRow("One") << "createOne" << "objectOne";
1179 QTest::newRow("Two") << "createTwo" << "objectTwo";
1180 QTest::newRow("Three") << "createThree" << "objectThree";
1184 Test using createQmlObject to dynamically generate an item
1185 Also using createComponent is tested.
1187 void tst_qdeclarativeecmascript::dynamicCreation()
1189 QFETCH(QString, method);
1190 QFETCH(QString, createdName);
1192 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1193 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1194 QVERIFY(object != 0);
1196 QMetaObject::invokeMethod(object, method.toUtf8());
1197 QObject *created = object->objectProperty();
1199 QCOMPARE(created->objectName(), createdName);
1205 Tests the destroy function
1207 void tst_qdeclarativeecmascript::dynamicDestruction()
1210 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
1211 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1212 QVERIFY(object != 0);
1213 QDeclarativeGuard<QObject> createdQmlObject = 0;
1215 QMetaObject::invokeMethod(object, "create");
1216 createdQmlObject = object->objectProperty();
1217 QVERIFY(createdQmlObject);
1218 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1220 QMetaObject::invokeMethod(object, "killOther");
1221 QVERIFY(createdQmlObject);
1222 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1223 QVERIFY(createdQmlObject);
1224 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1225 if (createdQmlObject) {
1227 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1230 QVERIFY(!createdQmlObject);
1232 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1233 QMetaObject::invokeMethod(object, "killMe");
1236 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1241 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
1242 QObject *o = component.create();
1245 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1247 QMetaObject::invokeMethod(o, "create");
1249 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1251 QMetaObject::invokeMethod(o, "destroy");
1253 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1255 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1262 tests that id.toString() works
1264 void tst_qdeclarativeecmascript::objectToString()
1266 QDeclarativeComponent component(&engine, testFileUrl("declarativeToString.qml"));
1267 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1268 QVERIFY(object != 0);
1269 QMetaObject::invokeMethod(object, "testToString");
1270 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1271 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1277 tests that id.hasOwnProperty() works
1279 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1281 QUrl url = testFileUrl("declarativeHasOwnProperty.qml");
1282 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1283 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1284 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1286 QDeclarativeComponent component(&engine, url);
1287 QObject *object = component.create();
1288 QVERIFY(object != 0);
1290 // test QObjects in QML
1291 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1292 QVERIFY(object->property("result").value<bool>() == true);
1293 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1294 QVERIFY(object->property("result").value<bool>() == false);
1296 // now test other types in QML
1297 QObject *child = object->findChild<QObject*>("typeObj");
1298 QVERIFY(child != 0);
1299 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1300 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1301 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1302 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1303 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1304 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1305 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1306 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1307 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1308 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1309 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1310 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1312 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1313 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1314 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1315 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1316 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1317 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1318 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1319 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1320 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1326 Tests bindings that indirectly cause their own deletion work.
1328 This test is best run under valgrind to ensure no invalid memory access occur.
1330 void tst_qdeclarativeecmascript::selfDeletingBinding()
1333 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
1334 QObject *object = component.create();
1335 QVERIFY(object != 0);
1336 object->setProperty("triggerDelete", true);
1341 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
1342 QObject *object = component.create();
1343 QVERIFY(object != 0);
1344 object->setProperty("triggerDelete", true);
1350 Test that extended object properties can be accessed.
1352 This test a regression where this used to crash. The issue was specificially
1353 for extended objects that did not include a synthesized meta object (so non-root
1354 and no synthesiszed properties).
1356 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1358 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
1359 QObject *object = component.create();
1360 QVERIFY(object != 0);
1365 Test that extended object properties can be accessed correctly.
1367 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
1369 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
1370 QObject *object = component.create();
1371 QVERIFY(object != 0);
1373 QVariant returnValue;
1374 QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
1375 QCOMPARE(returnValue.toInt(), 42);
1380 Test file/lineNumbers for binding/Script errors.
1382 void tst_qdeclarativeecmascript::scriptErrors()
1384 QDeclarativeComponent component(&engine, testFileUrl("scriptErrors.qml"));
1385 QString url = component.url().toString();
1387 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1388 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1389 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1390 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1391 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1392 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1393 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1394 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1396 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1397 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1398 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1399 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1400 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1401 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1402 QVERIFY(object != 0);
1404 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1405 emit object->basicSignal();
1407 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1408 emit object->anotherBasicSignal();
1410 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1411 emit object->thirdBasicSignal();
1417 Test file/lineNumbers for inline functions.
1419 void tst_qdeclarativeecmascript::functionErrors()
1421 QDeclarativeComponent component(&engine, testFileUrl("functionErrors.qml"));
1422 QString url = component.url().toString();
1424 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1426 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1428 QObject *object = component.create();
1429 QVERIFY(object != 0);
1432 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1433 QDeclarativeComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
1434 url = componentTwo.url().toString();
1435 object = componentTwo.create();
1436 QVERIFY(object != 0);
1438 QString srpname = object->property("srp_name").toString();
1440 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1441 + QLatin1String(" is not a function");
1442 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1443 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1448 Test various errors that can occur when assigning a property from script
1450 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1452 QDeclarativeComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
1454 QString url = component.url().toString();
1456 QObject *object = component.create();
1457 QVERIFY(object != 0);
1459 QCOMPARE(object->property("test1").toBool(), true);
1460 QCOMPARE(object->property("test2").toBool(), true);
1466 Test bindings still work when the reeval is triggered from within
1469 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1471 QDeclarativeComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
1472 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1473 QVERIFY(object != 0);
1475 QCOMPARE(object->property("base").toReal(), 50.);
1476 QCOMPARE(object->property("test1").toReal(), 50.);
1477 QCOMPARE(object->property("test2").toReal(), 50.);
1479 object->basicSignal();
1481 QCOMPARE(object->property("base").toReal(), 200.);
1482 QCOMPARE(object->property("test1").toReal(), 200.);
1483 QCOMPARE(object->property("test2").toReal(), 200.);
1485 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1487 QCOMPARE(object->property("base").toReal(), 400.);
1488 QCOMPARE(object->property("test1").toReal(), 400.);
1489 QCOMPARE(object->property("test2").toReal(), 400.);
1495 Test that list properties can be iterated from ECMAScript
1497 void tst_qdeclarativeecmascript::listProperties()
1499 QDeclarativeComponent component(&engine, testFileUrl("listProperties.qml"));
1500 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1501 QVERIFY(object != 0);
1503 QCOMPARE(object->property("test1").toInt(), 21);
1504 QCOMPARE(object->property("test2").toInt(), 2);
1505 QCOMPARE(object->property("test3").toBool(), true);
1506 QCOMPARE(object->property("test4").toBool(), true);
1511 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1513 QDeclarativeComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
1514 QString url = component.url().toString();
1516 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1518 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1519 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1520 QVERIFY(object != 0);
1522 QCOMPARE(object->property("test").toBool(), false);
1524 MyQmlObject object2;
1525 MyQmlObject object3;
1526 object2.setObjectProperty(&object3);
1527 object->setObjectProperty(&object2);
1529 QCOMPARE(object->property("test").toBool(), true);
1534 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1536 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
1537 QString url = component.url().toString();
1539 QString warning = component.url().toString() + ":6: Error: JS exception";
1541 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1542 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1543 QVERIFY(object != 0);
1547 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1549 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
1550 QString url = component.url().toString();
1552 QString warning = component.url().toString() + ":5: Error: JS exception";
1554 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1555 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1556 QVERIFY(object != 0);
1560 static int transientErrorsMsgCount = 0;
1561 static void transientErrorsMsgHandler(QtMsgType, const char *)
1563 ++transientErrorsMsgCount;
1566 // Check that transient binding errors are not displayed
1567 void tst_qdeclarativeecmascript::transientErrors()
1570 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
1572 transientErrorsMsgCount = 0;
1573 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1575 QObject *object = component.create();
1576 QVERIFY(object != 0);
1578 qInstallMsgHandler(old);
1580 QCOMPARE(transientErrorsMsgCount, 0);
1585 // One binding erroring multiple times, but then resolving
1587 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
1589 transientErrorsMsgCount = 0;
1590 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1592 QObject *object = component.create();
1593 QVERIFY(object != 0);
1595 qInstallMsgHandler(old);
1597 QCOMPARE(transientErrorsMsgCount, 0);
1603 // Check that errors during shutdown are minimized
1604 void tst_qdeclarativeecmascript::shutdownErrors()
1606 QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
1607 QObject *object = component.create();
1608 QVERIFY(object != 0);
1610 transientErrorsMsgCount = 0;
1611 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1615 qInstallMsgHandler(old);
1616 QCOMPARE(transientErrorsMsgCount, 0);
1619 void tst_qdeclarativeecmascript::compositePropertyType()
1621 QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
1623 QTest::ignoreMessage(QtDebugMsg, "hello world");
1624 QObject *object = qobject_cast<QObject *>(component.create());
1629 void tst_qdeclarativeecmascript::jsObject()
1631 QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
1632 QObject *object = component.create();
1633 QVERIFY(object != 0);
1635 QCOMPARE(object->property("test").toInt(), 92);
1640 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1643 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
1644 QObject *object = component.create();
1645 QVERIFY(object != 0);
1647 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1649 object->setProperty("setUndefined", true);
1651 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1653 object->setProperty("setUndefined", false);
1655 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1660 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
1661 QObject *object = component.create();
1662 QVERIFY(object != 0);
1664 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1666 QMetaObject::invokeMethod(object, "doReset");
1668 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1674 // Aliases to variant properties should work
1675 void tst_qdeclarativeecmascript::qtbug_22464()
1677 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
1678 QObject *object = component.create();
1679 QVERIFY(object != 0);
1681 QCOMPARE(object->property("test").toBool(), true);
1686 void tst_qdeclarativeecmascript::qtbug_21580()
1688 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
1690 QObject *object = component.create();
1691 QVERIFY(object != 0);
1693 QCOMPARE(object->property("test").toBool(), true);
1699 void tst_qdeclarativeecmascript::bug1()
1701 QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
1702 QObject *object = component.create();
1703 QVERIFY(object != 0);
1705 QCOMPARE(object->property("test").toInt(), 14);
1707 object->setProperty("a", 11);
1709 QCOMPARE(object->property("test").toInt(), 3);
1711 object->setProperty("b", true);
1713 QCOMPARE(object->property("test").toInt(), 9);
1718 void tst_qdeclarativeecmascript::bug2()
1720 QDeclarativeComponent component(&engine);
1721 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1723 QObject *object = component.create();
1724 QVERIFY(object != 0);
1729 // Don't crash in createObject when the component has errors.
1730 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1732 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1733 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1734 QVERIFY(object != 0);
1736 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1737 QMetaObject::invokeMethod(object, "dontCrash");
1738 QObject *created = object->objectProperty();
1739 QVERIFY(created == 0);
1744 // ownership transferred to JS, ensure that GC runs the dtor
1745 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1748 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1750 // allow the engine to go out of scope too.
1752 QDeclarativeEngine dcoEngine;
1753 QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
1754 QObject *object = component.create();
1755 QVERIFY(object != 0);
1756 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1757 QVERIFY(mdcdo != 0);
1758 mdcdo->setDtorCount(&dtorCount);
1760 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1761 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1763 // we do this once manually, but it should be done automatically
1764 // when the engine goes out of scope (since it should gc in dtor)
1765 QMetaObject::invokeMethod(object, "performGc");
1768 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1774 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1775 QCOMPARE(dtorCount, expectedDtorCount);
1779 void tst_qdeclarativeecmascript::regExpBug()
1781 QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
1782 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1783 QVERIFY(object != 0);
1784 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1788 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1790 QString functionSource = QLatin1String("(function(object) { return ") +
1791 QLatin1String(source) + QLatin1String(" })");
1793 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1796 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1797 if (function.IsEmpty())
1799 v8::Handle<v8::Value> args[] = { o };
1800 function->Call(engine->global(), 1, args);
1801 return tc.HasCaught();
1804 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1805 const char *source, v8::Handle<v8::Value> result)
1807 QString functionSource = QLatin1String("(function(object) { return ") +
1808 QLatin1String(source) + QLatin1String(" })");
1810 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1813 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1814 if (function.IsEmpty())
1816 v8::Handle<v8::Value> args[] = { o };
1818 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1823 return value->StrictEquals(result);
1826 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1829 QString functionSource = QLatin1String("(function(object) { return ") +
1830 QLatin1String(source) + QLatin1String(" })");
1832 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1834 return v8::Handle<v8::Value>();
1835 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1836 if (function.IsEmpty())
1837 return v8::Handle<v8::Value>();
1838 v8::Handle<v8::Value> args[] = { o };
1840 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1843 return v8::Handle<v8::Value>();
1847 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1848 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1849 #define EVALUATE(source) evaluate(engine, object, source)
1851 void tst_qdeclarativeecmascript::callQtInvokables()
1853 MyInvokableObject o;
1855 QDeclarativeEngine qmlengine;
1856 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1858 QV8Engine *engine = ep->v8engine();
1860 v8::HandleScope handle_scope;
1861 v8::Context::Scope scope(engine->context());
1863 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1865 // Non-existent methods
1867 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1868 QCOMPARE(o.error(), false);
1869 QCOMPARE(o.invoked(), -1);
1870 QCOMPARE(o.actuals().count(), 0);
1873 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1874 QCOMPARE(o.error(), false);
1875 QCOMPARE(o.invoked(), -1);
1876 QCOMPARE(o.actuals().count(), 0);
1878 // Insufficient arguments
1880 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1881 QCOMPARE(o.error(), false);
1882 QCOMPARE(o.invoked(), -1);
1883 QCOMPARE(o.actuals().count(), 0);
1886 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1887 QCOMPARE(o.error(), false);
1888 QCOMPARE(o.invoked(), -1);
1889 QCOMPARE(o.actuals().count(), 0);
1891 // Excessive arguments
1893 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1894 QCOMPARE(o.error(), false);
1895 QCOMPARE(o.invoked(), 8);
1896 QCOMPARE(o.actuals().count(), 1);
1897 QCOMPARE(o.actuals().at(0), QVariant(10));
1900 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1901 QCOMPARE(o.error(), false);
1902 QCOMPARE(o.invoked(), 9);
1903 QCOMPARE(o.actuals().count(), 2);
1904 QCOMPARE(o.actuals().at(0), QVariant(10));
1905 QCOMPARE(o.actuals().at(1), QVariant(11));
1907 // Test return types
1909 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1910 QCOMPARE(o.error(), false);
1911 QCOMPARE(o.invoked(), 0);
1912 QCOMPARE(o.actuals().count(), 0);
1915 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1916 QCOMPARE(o.error(), false);
1917 QCOMPARE(o.invoked(), 1);
1918 QCOMPARE(o.actuals().count(), 0);
1921 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1922 QCOMPARE(o.error(), false);
1923 QCOMPARE(o.invoked(), 2);
1924 QCOMPARE(o.actuals().count(), 0);
1928 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1929 QVERIFY(!ret.IsEmpty());
1930 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1931 QCOMPARE(o.error(), false);
1932 QCOMPARE(o.invoked(), 3);
1933 QCOMPARE(o.actuals().count(), 0);
1938 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1939 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1940 QCOMPARE(o.error(), false);
1941 QCOMPARE(o.invoked(), 4);
1942 QCOMPARE(o.actuals().count(), 0);
1946 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1947 QCOMPARE(o.error(), false);
1948 QCOMPARE(o.invoked(), 5);
1949 QCOMPARE(o.actuals().count(), 0);
1953 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1954 QVERIFY(ret->IsString());
1955 QCOMPARE(engine->toString(ret), QString("Hello world"));
1956 QCOMPARE(o.error(), false);
1957 QCOMPARE(o.invoked(), 6);
1958 QCOMPARE(o.actuals().count(), 0);
1962 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1963 QCOMPARE(o.error(), false);
1964 QCOMPARE(o.invoked(), 7);
1965 QCOMPARE(o.actuals().count(), 0);
1969 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1970 QCOMPARE(o.error(), false);
1971 QCOMPARE(o.invoked(), 8);
1972 QCOMPARE(o.actuals().count(), 1);
1973 QCOMPARE(o.actuals().at(0), QVariant(94));
1976 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1977 QCOMPARE(o.error(), false);
1978 QCOMPARE(o.invoked(), 8);
1979 QCOMPARE(o.actuals().count(), 1);
1980 QCOMPARE(o.actuals().at(0), QVariant(94));
1983 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1984 QCOMPARE(o.error(), false);
1985 QCOMPARE(o.invoked(), 8);
1986 QCOMPARE(o.actuals().count(), 1);
1987 QCOMPARE(o.actuals().at(0), QVariant(0));
1990 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1991 QCOMPARE(o.error(), false);
1992 QCOMPARE(o.invoked(), 8);
1993 QCOMPARE(o.actuals().count(), 1);
1994 QCOMPARE(o.actuals().at(0), QVariant(0));
1997 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1998 QCOMPARE(o.error(), false);
1999 QCOMPARE(o.invoked(), 8);
2000 QCOMPARE(o.actuals().count(), 1);
2001 QCOMPARE(o.actuals().at(0), QVariant(0));
2004 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2005 QCOMPARE(o.error(), false);
2006 QCOMPARE(o.invoked(), 8);
2007 QCOMPARE(o.actuals().count(), 1);
2008 QCOMPARE(o.actuals().at(0), QVariant(0));
2011 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2012 QCOMPARE(o.error(), false);
2013 QCOMPARE(o.invoked(), 9);
2014 QCOMPARE(o.actuals().count(), 2);
2015 QCOMPARE(o.actuals().at(0), QVariant(122));
2016 QCOMPARE(o.actuals().at(1), QVariant(9));
2019 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2020 QCOMPARE(o.error(), false);
2021 QCOMPARE(o.invoked(), 10);
2022 QCOMPARE(o.actuals().count(), 1);
2023 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2026 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2027 QCOMPARE(o.error(), false);
2028 QCOMPARE(o.invoked(), 10);
2029 QCOMPARE(o.actuals().count(), 1);
2030 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2033 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2034 QCOMPARE(o.error(), false);
2035 QCOMPARE(o.invoked(), 10);
2036 QCOMPARE(o.actuals().count(), 1);
2037 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2040 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2041 QCOMPARE(o.error(), false);
2042 QCOMPARE(o.invoked(), 10);
2043 QCOMPARE(o.actuals().count(), 1);
2044 QCOMPARE(o.actuals().at(0), QVariant(0));
2047 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2048 QCOMPARE(o.error(), false);
2049 QCOMPARE(o.invoked(), 10);
2050 QCOMPARE(o.actuals().count(), 1);
2051 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2054 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2055 QCOMPARE(o.error(), false);
2056 QCOMPARE(o.invoked(), 10);
2057 QCOMPARE(o.actuals().count(), 1);
2058 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2061 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2062 QCOMPARE(o.error(), false);
2063 QCOMPARE(o.invoked(), 11);
2064 QCOMPARE(o.actuals().count(), 1);
2065 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2068 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2069 QCOMPARE(o.error(), false);
2070 QCOMPARE(o.invoked(), 11);
2071 QCOMPARE(o.actuals().count(), 1);
2072 QCOMPARE(o.actuals().at(0), QVariant("19"));
2076 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2077 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2078 QCOMPARE(o.error(), false);
2079 QCOMPARE(o.invoked(), 11);
2080 QCOMPARE(o.actuals().count(), 1);
2081 QCOMPARE(o.actuals().at(0), QVariant(expected));
2085 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2086 QCOMPARE(o.error(), false);
2087 QCOMPARE(o.invoked(), 11);
2088 QCOMPARE(o.actuals().count(), 1);
2089 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2092 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2093 QCOMPARE(o.error(), false);
2094 QCOMPARE(o.invoked(), 11);
2095 QCOMPARE(o.actuals().count(), 1);
2096 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2099 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2100 QCOMPARE(o.error(), false);
2101 QCOMPARE(o.invoked(), 12);
2102 QCOMPARE(o.actuals().count(), 1);
2103 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2106 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2107 QCOMPARE(o.error(), false);
2108 QCOMPARE(o.invoked(), 12);
2109 QCOMPARE(o.actuals().count(), 1);
2110 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2113 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2114 QCOMPARE(o.error(), false);
2115 QCOMPARE(o.invoked(), 12);
2116 QCOMPARE(o.actuals().count(), 1);
2117 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2120 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2121 QCOMPARE(o.error(), false);
2122 QCOMPARE(o.invoked(), 12);
2123 QCOMPARE(o.actuals().count(), 1);
2124 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2127 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2128 QCOMPARE(o.error(), false);
2129 QCOMPARE(o.invoked(), 12);
2130 QCOMPARE(o.actuals().count(), 1);
2131 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2134 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2135 QCOMPARE(o.error(), false);
2136 QCOMPARE(o.invoked(), 12);
2137 QCOMPARE(o.actuals().count(), 1);
2138 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2141 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2142 QCOMPARE(o.error(), false);
2143 QCOMPARE(o.invoked(), 13);
2144 QCOMPARE(o.actuals().count(), 1);
2145 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2148 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2149 QCOMPARE(o.error(), false);
2150 QCOMPARE(o.invoked(), 13);
2151 QCOMPARE(o.actuals().count(), 1);
2152 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2155 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2156 QCOMPARE(o.error(), false);
2157 QCOMPARE(o.invoked(), 13);
2158 QCOMPARE(o.actuals().count(), 1);
2159 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2162 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2163 QCOMPARE(o.error(), false);
2164 QCOMPARE(o.invoked(), 13);
2165 QCOMPARE(o.actuals().count(), 1);
2166 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2169 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2170 QCOMPARE(o.error(), false);
2171 QCOMPARE(o.invoked(), 13);
2172 QCOMPARE(o.actuals().count(), 1);
2173 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2176 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2177 QCOMPARE(o.error(), false);
2178 QCOMPARE(o.invoked(), 14);
2179 QCOMPARE(o.actuals().count(), 1);
2180 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2183 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2184 QCOMPARE(o.error(), false);
2185 QCOMPARE(o.invoked(), 14);
2186 QCOMPARE(o.actuals().count(), 1);
2187 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2190 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2191 QCOMPARE(o.error(), false);
2192 QCOMPARE(o.invoked(), 14);
2193 QCOMPARE(o.actuals().count(), 1);
2194 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2197 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2198 QCOMPARE(o.error(), false);
2199 QCOMPARE(o.invoked(), 14);
2200 QCOMPARE(o.actuals().count(), 1);
2201 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2204 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2205 QCOMPARE(o.error(), false);
2206 QCOMPARE(o.invoked(), 15);
2207 QCOMPARE(o.actuals().count(), 2);
2208 QCOMPARE(o.actuals().at(0), QVariant(4));
2209 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2212 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2213 QCOMPARE(o.error(), false);
2214 QCOMPARE(o.invoked(), 15);
2215 QCOMPARE(o.actuals().count(), 2);
2216 QCOMPARE(o.actuals().at(0), QVariant(8));
2217 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2220 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2221 QCOMPARE(o.error(), false);
2222 QCOMPARE(o.invoked(), 15);
2223 QCOMPARE(o.actuals().count(), 2);
2224 QCOMPARE(o.actuals().at(0), QVariant(3));
2225 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2228 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2229 QCOMPARE(o.error(), false);
2230 QCOMPARE(o.invoked(), 15);
2231 QCOMPARE(o.actuals().count(), 2);
2232 QCOMPARE(o.actuals().at(0), QVariant(44));
2233 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2236 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2237 QCOMPARE(o.error(), false);
2238 QCOMPARE(o.invoked(), -1);
2239 QCOMPARE(o.actuals().count(), 0);
2242 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2243 QCOMPARE(o.error(), false);
2244 QCOMPARE(o.invoked(), 16);
2245 QCOMPARE(o.actuals().count(), 1);
2246 QCOMPARE(o.actuals().at(0), QVariant(10));
2249 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2250 QCOMPARE(o.error(), false);
2251 QCOMPARE(o.invoked(), 17);
2252 QCOMPARE(o.actuals().count(), 2);
2253 QCOMPARE(o.actuals().at(0), QVariant(10));
2254 QCOMPARE(o.actuals().at(1), QVariant(11));
2257 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2258 QCOMPARE(o.error(), false);
2259 QCOMPARE(o.invoked(), 18);
2260 QCOMPARE(o.actuals().count(), 1);
2261 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2264 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2265 QCOMPARE(o.error(), false);
2266 QCOMPARE(o.invoked(), 19);
2267 QCOMPARE(o.actuals().count(), 1);
2268 QCOMPARE(o.actuals().at(0), QVariant(9));
2271 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2272 QCOMPARE(o.error(), false);
2273 QCOMPARE(o.invoked(), 20);
2274 QCOMPARE(o.actuals().count(), 2);
2275 QCOMPARE(o.actuals().at(0), QVariant(10));
2276 QCOMPARE(o.actuals().at(1), QVariant(19));
2279 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2280 QCOMPARE(o.error(), false);
2281 QCOMPARE(o.invoked(), 20);
2282 QCOMPARE(o.actuals().count(), 2);
2283 QCOMPARE(o.actuals().at(0), QVariant(10));
2284 QCOMPARE(o.actuals().at(1), QVariant(13));
2287 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2288 QCOMPARE(o.error(), false);
2289 QCOMPARE(o.invoked(), -3);
2290 QCOMPARE(o.actuals().count(), 1);
2291 QCOMPARE(o.actuals().at(0), QVariant(9));
2294 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2295 QCOMPARE(o.error(), false);
2296 QCOMPARE(o.invoked(), 21);
2297 QCOMPARE(o.actuals().count(), 2);
2298 QCOMPARE(o.actuals().at(0), QVariant(9));
2299 QCOMPARE(o.actuals().at(1), QVariant());
2302 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2303 QCOMPARE(o.error(), false);
2304 QCOMPARE(o.invoked(), 21);
2305 QCOMPARE(o.actuals().count(), 2);
2306 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2307 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2310 // QTBUG-13047 (check that you can pass registered object types as args)
2311 void tst_qdeclarativeecmascript::invokableObjectArg()
2313 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
2315 QObject *o = component.create();
2317 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2319 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2324 // QTBUG-13047 (check that you can return registered object types from methods)
2325 void tst_qdeclarativeecmascript::invokableObjectRet()
2327 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
2329 QObject *o = component.create();
2331 QCOMPARE(o->property("test").toBool(), true);
2336 void tst_qdeclarativeecmascript::listToVariant()
2338 QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
2340 MyQmlContainer container;
2342 QDeclarativeContext context(engine.rootContext());
2343 context.setContextObject(&container);
2345 QObject *object = component.create(&context);
2346 QVERIFY(object != 0);
2348 QVariant v = object->property("test");
2349 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2350 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2356 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2357 void tst_qdeclarativeecmascript::listAssignment()
2359 QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
2360 QObject *obj = component.create();
2361 QCOMPARE(obj->property("list1length").toInt(), 2);
2362 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2363 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2364 QCOMPARE(list1.count(&list1), list2.count(&list2));
2365 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2366 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2371 void tst_qdeclarativeecmascript::multiEngineObject()
2374 obj.setStringProperty("Howdy planet");
2376 QDeclarativeEngine e1;
2377 e1.rootContext()->setContextProperty("thing", &obj);
2378 QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
2380 QDeclarativeEngine e2;
2381 e2.rootContext()->setContextProperty("thing", &obj);
2382 QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
2384 QObject *o1 = c1.create();
2385 QObject *o2 = c2.create();
2387 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2388 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2394 // Test that references to QObjects are cleanup when the object is destroyed
2395 void tst_qdeclarativeecmascript::deletedObject()
2397 QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
2399 QObject *object = component.create();
2401 QCOMPARE(object->property("test1").toBool(), true);
2402 QCOMPARE(object->property("test2").toBool(), true);
2403 QCOMPARE(object->property("test3").toBool(), true);
2404 QCOMPARE(object->property("test4").toBool(), true);
2409 void tst_qdeclarativeecmascript::attachedPropertyScope()
2411 QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
2413 QObject *object = component.create();
2414 QVERIFY(object != 0);
2416 MyQmlAttachedObject *attached =
2417 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2418 QVERIFY(attached != 0);
2420 QCOMPARE(object->property("value2").toInt(), 0);
2422 attached->emitMySignal();
2424 QCOMPARE(object->property("value2").toInt(), 9);
2429 void tst_qdeclarativeecmascript::scriptConnect()
2432 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
2434 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2435 QVERIFY(object != 0);
2437 QCOMPARE(object->property("test").toBool(), false);
2438 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2439 QCOMPARE(object->property("test").toBool(), true);
2445 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
2447 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2448 QVERIFY(object != 0);
2450 QCOMPARE(object->property("test").toBool(), false);
2451 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2452 QCOMPARE(object->property("test").toBool(), true);
2458 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
2460 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2461 QVERIFY(object != 0);
2463 QCOMPARE(object->property("test").toBool(), false);
2464 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2465 QCOMPARE(object->property("test").toBool(), true);
2471 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
2473 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2474 QVERIFY(object != 0);
2476 QCOMPARE(object->methodCalled(), false);
2477 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2478 QCOMPARE(object->methodCalled(), true);
2484 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
2486 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2487 QVERIFY(object != 0);
2489 QCOMPARE(object->methodCalled(), false);
2490 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2491 QCOMPARE(object->methodCalled(), true);
2497 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
2499 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2500 QVERIFY(object != 0);
2502 QCOMPARE(object->property("test").toInt(), 0);
2503 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2504 QCOMPARE(object->property("test").toInt(), 2);
2510 void tst_qdeclarativeecmascript::scriptDisconnect()
2513 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
2515 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2516 QVERIFY(object != 0);
2518 QCOMPARE(object->property("test").toInt(), 0);
2519 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2520 QCOMPARE(object->property("test").toInt(), 1);
2521 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2522 QCOMPARE(object->property("test").toInt(), 2);
2523 emit object->basicSignal();
2524 QCOMPARE(object->property("test").toInt(), 2);
2525 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2526 QCOMPARE(object->property("test").toInt(), 2);
2532 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
2534 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2535 QVERIFY(object != 0);
2537 QCOMPARE(object->property("test").toInt(), 0);
2538 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2539 QCOMPARE(object->property("test").toInt(), 1);
2540 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2541 QCOMPARE(object->property("test").toInt(), 2);
2542 emit object->basicSignal();
2543 QCOMPARE(object->property("test").toInt(), 2);
2544 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2545 QCOMPARE(object->property("test").toInt(), 2);
2551 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
2553 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2554 QVERIFY(object != 0);
2556 QCOMPARE(object->property("test").toInt(), 0);
2557 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2558 QCOMPARE(object->property("test").toInt(), 1);
2559 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2560 QCOMPARE(object->property("test").toInt(), 2);
2561 emit object->basicSignal();
2562 QCOMPARE(object->property("test").toInt(), 2);
2563 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2564 QCOMPARE(object->property("test").toInt(), 3);
2569 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
2571 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2572 QVERIFY(object != 0);
2574 QCOMPARE(object->property("test").toInt(), 0);
2575 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2576 QCOMPARE(object->property("test").toInt(), 1);
2577 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2578 QCOMPARE(object->property("test").toInt(), 2);
2579 emit object->basicSignal();
2580 QCOMPARE(object->property("test").toInt(), 2);
2581 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2582 QCOMPARE(object->property("test").toInt(), 3);
2588 class OwnershipObject : public QObject
2592 OwnershipObject() { object = new QObject; }
2594 QPointer<QObject> object;
2597 QObject *getObject() { return object; }
2600 void tst_qdeclarativeecmascript::ownership()
2602 OwnershipObject own;
2603 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2604 context->setContextObject(&own);
2607 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2609 QVERIFY(own.object != 0);
2611 QObject *object = component.create(context);
2613 engine.collectGarbage();
2615 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2617 QVERIFY(own.object == 0);
2622 own.object = new QObject(&own);
2625 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2627 QVERIFY(own.object != 0);
2629 QObject *object = component.create(context);
2631 engine.collectGarbage();
2633 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2635 QVERIFY(own.object != 0);
2643 class CppOwnershipReturnValue : public QObject
2647 CppOwnershipReturnValue() : value(0) {}
2648 ~CppOwnershipReturnValue() { delete value; }
2650 Q_INVOKABLE QObject *create() {
2651 value = new QObject;
2652 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2656 Q_INVOKABLE MyQmlObject *createQmlObject() {
2657 MyQmlObject *rv = new MyQmlObject;
2662 QPointer<QObject> value;
2666 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2667 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2669 CppOwnershipReturnValue source;
2672 QDeclarativeEngine engine;
2673 engine.rootContext()->setContextProperty("source", &source);
2675 QVERIFY(source.value == 0);
2677 QDeclarativeComponent component(&engine);
2678 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2680 QObject *object = component.create();
2682 QVERIFY(object != 0);
2683 QVERIFY(source.value != 0);
2688 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2690 QVERIFY(source.value != 0);
2694 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2696 CppOwnershipReturnValue source;
2699 QDeclarativeEngine engine;
2700 engine.rootContext()->setContextProperty("source", &source);
2702 QVERIFY(source.value == 0);
2704 QDeclarativeComponent component(&engine);
2705 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2707 QObject *object = component.create();
2709 QVERIFY(object != 0);
2710 QVERIFY(source.value != 0);
2715 engine.collectGarbage();
2716 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2718 QVERIFY(source.value == 0);
2721 class QListQObjectMethodsObject : public QObject
2725 QListQObjectMethodsObject() {
2726 m_objects.append(new MyQmlObject());
2727 m_objects.append(new MyQmlObject());
2730 ~QListQObjectMethodsObject() {
2731 qDeleteAll(m_objects);
2735 QList<QObject *> getObjects() { return m_objects; }
2738 QList<QObject *> m_objects;
2741 // Tests that returning a QList<QObject*> from a method works
2742 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2744 QListQObjectMethodsObject obj;
2745 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2746 context->setContextObject(&obj);
2748 QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
2750 QObject *object = component.create(context);
2752 QCOMPARE(object->property("test").toInt(), 2);
2753 QCOMPARE(object->property("test2").toBool(), true);
2760 void tst_qdeclarativeecmascript::strictlyEquals()
2762 QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
2764 QObject *object = component.create();
2765 QVERIFY(object != 0);
2767 QCOMPARE(object->property("test1").toBool(), true);
2768 QCOMPARE(object->property("test2").toBool(), true);
2769 QCOMPARE(object->property("test3").toBool(), true);
2770 QCOMPARE(object->property("test4").toBool(), true);
2771 QCOMPARE(object->property("test5").toBool(), true);
2772 QCOMPARE(object->property("test6").toBool(), true);
2773 QCOMPARE(object->property("test7").toBool(), true);
2774 QCOMPARE(object->property("test8").toBool(), true);
2779 void tst_qdeclarativeecmascript::compiled()
2781 QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
2783 QObject *object = component.create();
2784 QVERIFY(object != 0);
2786 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2787 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2788 QCOMPARE(object->property("test3").toBool(), true);
2789 QCOMPARE(object->property("test4").toBool(), false);
2790 QCOMPARE(object->property("test5").toBool(), false);
2791 QCOMPARE(object->property("test6").toBool(), true);
2793 QCOMPARE(object->property("test7").toInt(), 185);
2794 QCOMPARE(object->property("test8").toInt(), 167);
2795 QCOMPARE(object->property("test9").toBool(), true);
2796 QCOMPARE(object->property("test10").toBool(), false);
2797 QCOMPARE(object->property("test11").toBool(), false);
2798 QCOMPARE(object->property("test12").toBool(), true);
2800 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2801 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2802 QCOMPARE(object->property("test15").toBool(), false);
2803 QCOMPARE(object->property("test16").toBool(), true);
2805 QCOMPARE(object->property("test17").toInt(), 5);
2806 QCOMPARE(object->property("test18").toReal(), qreal(176));
2807 QCOMPARE(object->property("test19").toInt(), 7);
2808 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2809 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2810 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2811 QCOMPARE(object->property("test23").toBool(), true);
2812 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2813 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2818 // Test that numbers assigned in bindings as strings work consistently
2819 void tst_qdeclarativeecmascript::numberAssignment()
2821 QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
2823 QObject *object = component.create();
2824 QVERIFY(object != 0);
2826 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2827 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2828 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2829 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2830 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2832 QCOMPARE(object->property("test5"), QVariant((int)7));
2833 QCOMPARE(object->property("test6"), QVariant((int)7));
2834 QCOMPARE(object->property("test7"), QVariant((int)6));
2835 QCOMPARE(object->property("test8"), QVariant((int)6));
2837 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2838 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2839 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2840 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2845 void tst_qdeclarativeecmascript::propertySplicing()
2847 QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
2849 QObject *object = component.create();
2850 QVERIFY(object != 0);
2852 QCOMPARE(object->property("test").toBool(), true);
2858 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2860 QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
2862 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2863 QVERIFY(object != 0);
2865 MyQmlObject::MyType type;
2866 type.value = 0x8971123;
2867 emit object->signalWithUnknownType(type);
2869 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2871 QCOMPARE(result.value, type.value);
2877 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2879 QTest::addColumn<QString>("expression");
2880 QTest::addColumn<QString>("compare");
2882 QString compareStrict("(function(a, b) { return a === b; })");
2883 QTest::newRow("true") << "true" << compareStrict;
2884 QTest::newRow("undefined") << "undefined" << compareStrict;
2885 QTest::newRow("null") << "null" << compareStrict;
2886 QTest::newRow("123") << "123" << compareStrict;
2887 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2889 QString comparePropertiesStrict(
2891 " if (typeof b != 'object')"
2893 " var props = Object.getOwnPropertyNames(b);"
2894 " for (var i = 0; i < props.length; ++i) {"
2895 " var p = props[i];"
2896 " return arguments.callee(a[p], b[p]);"
2899 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2900 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2903 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2905 QFETCH(QString, expression);
2906 QFETCH(QString, compare);
2908 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2909 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2910 QVERIFY(object != 0);
2912 QJSValue value = engine.evaluate(expression);
2913 QVERIFY(!engine.hasUncaughtException());
2914 object->setProperty("expression", expression);
2915 object->setProperty("compare", compare);
2916 object->setProperty("pass", false);
2918 emit object->signalWithVariant(QVariant::fromValue(value));
2919 QVERIFY(object->property("pass").toBool());
2922 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2924 signalWithJSValueInVariant_data();
2927 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2929 QFETCH(QString, expression);
2930 QFETCH(QString, compare);
2932 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2933 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2934 QVERIFY(object != 0);
2937 QJSValue value = engine2.evaluate(expression);
2938 QVERIFY(!engine2.hasUncaughtException());
2939 object->setProperty("expression", expression);
2940 object->setProperty("compare", compare);
2941 object->setProperty("pass", false);
2943 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2944 emit object->signalWithVariant(QVariant::fromValue(value));
2945 QVERIFY(!object->property("pass").toBool());
2948 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2950 signalWithJSValueInVariant_data();
2953 void tst_qdeclarativeecmascript::signalWithQJSValue()
2955 QFETCH(QString, expression);
2956 QFETCH(QString, compare);
2958 QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
2959 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2960 QVERIFY(object != 0);
2962 QJSValue value = engine.evaluate(expression);
2963 QVERIFY(!engine.hasUncaughtException());
2964 object->setProperty("expression", expression);
2965 object->setProperty("compare", compare);
2966 object->setProperty("pass", false);
2968 emit object->signalWithQJSValue(value);
2970 QVERIFY(object->property("pass").toBool());
2971 QVERIFY(object->qjsvalue().strictlyEquals(value));
2974 void tst_qdeclarativeecmascript::moduleApi_data()
2976 QTest::addColumn<QUrl>("testfile");
2977 QTest::addColumn<QString>("errorMessage");
2978 QTest::addColumn<QStringList>("warningMessages");
2979 QTest::addColumn<QStringList>("readProperties");
2980 QTest::addColumn<QVariantList>("readExpectedValues");
2981 QTest::addColumn<QStringList>("writeProperties");
2982 QTest::addColumn<QVariantList>("writeValues");
2983 QTest::addColumn<QStringList>("readBackProperties");
2984 QTest::addColumn<QVariantList>("readBackExpectedValues");
2986 QTest::newRow("qobject, register + read + method")
2987 << testFileUrl("moduleapi/qobjectModuleApi.qml")
2990 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2991 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2992 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2998 QTest::newRow("script, register + read")
2999 << testFileUrl("moduleapi/scriptModuleApi.qml")
3002 << (QStringList() << "scriptTest")
3003 << (QVariantList() << 13)
3009 QTest::newRow("qobject, caching + read")
3010 << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
3013 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3014 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3020 QTest::newRow("script, caching + read")
3021 << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
3024 << (QStringList() << "scriptTest")
3025 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3031 QTest::newRow("qobject, writing + readonly constraints")
3032 << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
3034 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3035 << (QStringList() << "readOnlyProperty" << "writableProperty")
3036 << (QVariantList() << 20 << 50)
3037 << (QStringList() << "firstProperty" << "writableProperty")
3038 << (QVariantList() << 30 << 30)
3039 << (QStringList() << "readOnlyProperty" << "writableProperty")
3040 << (QVariantList() << 20 << 30);
3042 QTest::newRow("script, writing + readonly constraints")
3043 << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
3045 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3046 << (QStringList() << "readBack" << "unchanged")
3047 << (QVariantList() << 13 << 42)
3048 << (QStringList() << "firstProperty" << "secondProperty")
3049 << (QVariantList() << 30 << 30)
3050 << (QStringList() << "readBack" << "unchanged")
3051 << (QVariantList() << 30 << 42);
3053 QTest::newRow("qobject module API enum values in JS")
3054 << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
3057 << (QStringList() << "enumValue" << "enumMethod")
3058 << (QVariantList() << 42 << 30)
3064 QTest::newRow("qobject, invalid major version fail")
3065 << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
3066 << QString("QDeclarativeComponent: Component is not ready")
3075 QTest::newRow("qobject, invalid minor version fail")
3076 << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
3077 << QString("QDeclarativeComponent: Component is not ready")
3087 void tst_qdeclarativeecmascript::moduleApi()
3089 QFETCH(QUrl, testfile);
3090 QFETCH(QString, errorMessage);
3091 QFETCH(QStringList, warningMessages);
3092 QFETCH(QStringList, readProperties);
3093 QFETCH(QVariantList, readExpectedValues);
3094 QFETCH(QStringList, writeProperties);
3095 QFETCH(QVariantList, writeValues);
3096 QFETCH(QStringList, readBackProperties);
3097 QFETCH(QVariantList, readBackExpectedValues);
3099 QDeclarativeComponent component(&engine, testfile);
3101 if (!errorMessage.isEmpty())
3102 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3104 if (warningMessages.size())
3105 foreach (const QString &warning, warningMessages)
3106 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3108 QObject *object = component.create();
3109 if (!errorMessage.isEmpty()) {
3110 QVERIFY(object == 0);
3112 QVERIFY(object != 0);
3113 for (int i = 0; i < readProperties.size(); ++i)
3114 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3115 for (int i = 0; i < writeProperties.size(); ++i)
3116 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3117 for (int i = 0; i < readBackProperties.size(); ++i)
3118 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3123 void tst_qdeclarativeecmascript::importScripts_data()
3125 QTest::addColumn<QUrl>("testfile");
3126 QTest::addColumn<QString>("errorMessage");
3127 QTest::addColumn<QStringList>("warningMessages");
3128 QTest::addColumn<QStringList>("propertyNames");
3129 QTest::addColumn<QVariantList>("propertyValues");
3131 QTest::newRow("basic functionality")
3132 << testFileUrl("jsimport/testImport.qml")
3135 << (QStringList() << QLatin1String("importedScriptStringValue")
3136 << QLatin1String("importedScriptFunctionValue")
3137 << QLatin1String("importedModuleAttachedPropertyValue")
3138 << QLatin1String("importedModuleEnumValue"))
3139 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3144 QTest::newRow("import scoping")
3145 << testFileUrl("jsimport/testImportScoping.qml")
3148 << (QStringList() << QLatin1String("componentError"))
3149 << (QVariantList() << QVariant(5));
3151 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3152 << testFileUrl("jsimportfail/failOne.qml")
3154 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3155 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3156 << (QVariantList() << QVariant(QString()));
3158 QTest::newRow("javascript imports in an import should be private to the import scope")
3159 << testFileUrl("jsimportfail/failTwo.qml")
3161 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3162 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3163 << (QVariantList() << QVariant(QString()));
3165 QTest::newRow("module imports in an import should be private to the import scope")
3166 << testFileUrl("jsimportfail/failThree.qml")
3168 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3169 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3170 << (QVariantList() << QVariant(false));
3172 QTest::newRow("typenames in an import should be private to the import scope")
3173 << testFileUrl("jsimportfail/failFour.qml")
3175 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3176 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3177 << (QVariantList() << QVariant(0));
3179 QTest::newRow("import with imports has it's own activation scope")
3180 << testFileUrl("jsimportfail/failFive.qml")
3182 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3183 << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3184 << (QStringList() << QLatin1String("componentError"))
3185 << (QVariantList() << QVariant(0));
3187 QTest::newRow("import pragma library script")
3188 << testFileUrl("jsimport/testImportPragmaLibrary.qml")
3191 << (QStringList() << QLatin1String("testValue"))
3192 << (QVariantList() << QVariant(31));
3194 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3195 << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
3198 << (QStringList() << QLatin1String("testValue"))
3199 << (QVariantList() << QVariant(0));
3201 QTest::newRow("import pragma library script which has an import")
3202 << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
3205 << (QStringList() << QLatin1String("testValue"))
3206 << (QVariantList() << QVariant(55));
3208 QTest::newRow("import pragma library script which has a pragma library import")
3209 << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3212 << (QStringList() << QLatin1String("testValue"))
3213 << (QVariantList() << QVariant(18));
3216 void tst_qdeclarativeecmascript::importScripts()
3218 QFETCH(QUrl, testfile);
3219 QFETCH(QString, errorMessage);
3220 QFETCH(QStringList, warningMessages);
3221 QFETCH(QStringList, propertyNames);
3222 QFETCH(QVariantList, propertyValues);
3224 QDeclarativeComponent component(&engine, testfile);
3226 if (!errorMessage.isEmpty())
3227 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3229 if (warningMessages.size())
3230 foreach (const QString &warning, warningMessages)
3231 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3233 QObject *object = component.create();
3234 if (!errorMessage.isEmpty()) {
3235 QVERIFY(object == 0);
3237 QVERIFY(object != 0);
3238 for (int i = 0; i < propertyNames.size(); ++i)
3239 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3244 void tst_qdeclarativeecmascript::scarceResources_other()
3246 /* These tests require knowledge of state, since we test values after
3247 performing signal or function invocation. */
3249 QPixmap origPixmap(100, 100);
3250 origPixmap.fill(Qt::blue);
3251 QString srp_name, expectedWarning;
3252 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3253 ScarceResourceObject *eo = 0;
3255 QObject *object = 0;
3257 /* property var semantics */
3259 // test that scarce resources are handled properly in signal invocation
3260 QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
3261 object = varComponentTen.create();
3262 srsc = object->findChild<QObject*>("srsc");
3264 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3265 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3266 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3267 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3268 QMetaObject::invokeMethod(srsc, "testSignal");
3269 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3270 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3271 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3272 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3273 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3274 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3275 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3276 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3277 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3278 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3281 // test that scarce resources are handled properly from js functions in qml files
3282 QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
3283 object = varComponentEleven.create();
3284 QVERIFY(object != 0);
3285 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3286 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3287 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3288 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3289 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3290 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3291 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3292 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3293 QMetaObject::invokeMethod(object, "releaseScarceResource");
3294 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3295 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3296 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3297 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3300 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3301 QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
3302 object = varComponentTwelve.create();
3303 QVERIFY(object != 0);
3304 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3305 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3306 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3307 srp_name = object->property("srp_name").toString();
3308 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3309 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3310 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3311 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3312 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3313 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3314 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3317 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3318 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3319 QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
3320 object = varComponentThirteen.create();
3321 QVERIFY(object != 0);
3322 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3323 QMetaObject::invokeMethod(object, "assignVarProperty");
3324 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3325 QMetaObject::invokeMethod(object, "deassignVarProperty");
3326 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3329 /* property variant semantics */
3331 // test that scarce resources are handled properly in signal invocation
3332 QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
3333 object = variantComponentTen.create();
3334 QVERIFY(object != 0);
3335 srsc = object->findChild<QObject*>("srsc");
3337 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3338 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3339 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3340 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3341 QMetaObject::invokeMethod(srsc, "testSignal");
3342 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3343 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3344 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3345 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3346 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3347 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3348 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3349 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3350 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3351 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3354 // test that scarce resources are handled properly from js functions in qml files
3355 QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
3356 object = variantComponentEleven.create();
3357 QVERIFY(object != 0);
3358 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3359 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3360 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3361 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3362 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3363 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3364 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3365 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3366 QMetaObject::invokeMethod(object, "releaseScarceResource");
3367 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3368 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3369 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3370 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3373 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3374 QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
3375 object = variantComponentTwelve.create();
3376 QVERIFY(object != 0);
3377 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3378 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3379 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3380 srp_name = object->property("srp_name").toString();
3381 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3382 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3383 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3384 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3385 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3386 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3387 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3391 void tst_qdeclarativeecmascript::scarceResources_data()
3393 QTest::addColumn<QUrl>("qmlFile");
3394 QTest::addColumn<bool>("readDetachStatus");
3395 QTest::addColumn<bool>("expectedDetachStatus");
3396 QTest::addColumn<QStringList>("propertyNames");
3397 QTest::addColumn<QVariantList>("expectedValidity");
3398 QTest::addColumn<QVariantList>("expectedValues");
3399 QTest::addColumn<QStringList>("expectedErrors");
3401 QPixmap origPixmap(100, 100);
3402 origPixmap.fill(Qt::blue);
3404 /* property var semantics */
3406 // in the following three cases, the instance created from the component
3407 // has a property which is a copy of the scarce resource; hence, the
3408 // resource should NOT be detached prior to deletion of the object instance,
3409 // unless the resource is destroyed explicitly.
3410 QTest::newRow("var: import scarce resource copy directly")
3411 << testFileUrl("scarceResourceCopy.var.qml")
3413 << false // won't be detached, because assigned to property and not explicitly released
3414 << (QStringList() << QLatin1String("scarceResourceCopy"))
3415 << (QList<QVariant>() << true)
3416 << (QList<QVariant>() << origPixmap)
3419 QTest::newRow("var: import scarce resource copy from JS")
3420 << testFileUrl("scarceResourceCopyFromJs.var.qml")
3422 << false // won't be detached, because assigned to property and not explicitly released
3423 << (QStringList() << QLatin1String("scarceResourceCopy"))
3424 << (QList<QVariant>() << true)
3425 << (QList<QVariant>() << origPixmap)
3428 QTest::newRow("var: import released scarce resource copy from JS")
3429 << testFileUrl("scarceResourceDestroyedCopy.var.qml")
3431 << true // explicitly released, so it will be detached
3432 << (QStringList() << QLatin1String("scarceResourceCopy"))
3433 << (QList<QVariant>() << false)
3434 << (QList<QVariant>() << QVariant())
3437 // in the following three cases, no other copy should exist in memory,
3438 // and so it should be detached (unless explicitly preserved).
3439 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3440 << testFileUrl("scarceResourceTest.var.qml")
3442 << true // auto released, so it will be detached
3443 << (QStringList() << QLatin1String("scarceResourceTest"))
3444 << (QList<QVariant>() << true)
3445 << (QList<QVariant>() << QVariant(100))
3447 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3448 << testFileUrl("scarceResourceTestPreserve.var.qml")
3450 << false // won't be detached because we explicitly preserve it
3451 << (QStringList() << QLatin1String("scarceResourceTest"))
3452 << (QList<QVariant>() << true)
3453 << (QList<QVariant>() << QVariant(100))
3455 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3456 << testFileUrl("scarceResourceTestMultiple.var.qml")
3458 << true // will be detached because all resources were released manually or automatically.
3459 << (QStringList() << QLatin1String("scarceResourceTest"))
3460 << (QList<QVariant>() << true)
3461 << (QList<QVariant>() << QVariant(100))
3464 // In the following three cases, test that scarce resources are handled
3465 // correctly for imports.
3466 QTest::newRow("var: import with no binding")
3467 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3468 << false // cannot check detach status.
3471 << QList<QVariant>()
3472 << QList<QVariant>()
3474 QTest::newRow("var: import with binding without explicit preserve")
3475 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3478 << (QStringList() << QLatin1String("scarceResourceCopy"))
3479 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3480 << (QList<QVariant>() << QVariant())
3482 QTest::newRow("var: import with explicit release after binding evaluation")
3483 << testFileUrl("scarceResourceCopyImport.var.qml")
3486 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3487 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3488 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3490 QTest::newRow("var: import with different js objects")
3491 << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
3494 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3495 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3496 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3498 QTest::newRow("var: import with different js objects and explicit release")
3499 << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
3502 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3503 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3504 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3506 QTest::newRow("var: import with same js objects and explicit release")
3507 << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
3510 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3511 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3512 << (QList<QVariant>() << QVariant() << QVariant())
3514 QTest::newRow("var: binding with same js objects and explicit release")
3515 << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
3518 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3519 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3520 << (QList<QVariant>() << QVariant() << QVariant())
3524 /* property variant semantics */
3526 // in the following three cases, the instance created from the component
3527 // has a property which is a copy of the scarce resource; hence, the
3528 // resource should NOT be detached prior to deletion of the object instance,
3529 // unless the resource is destroyed explicitly.
3530 QTest::newRow("variant: import scarce resource copy directly")
3531 << testFileUrl("scarceResourceCopy.variant.qml")
3533 << false // won't be detached, because assigned to property and not explicitly released
3534 << (QStringList() << QLatin1String("scarceResourceCopy"))
3535 << (QList<QVariant>() << true)
3536 << (QList<QVariant>() << origPixmap)
3539 QTest::newRow("variant: import scarce resource copy from JS")
3540 << testFileUrl("scarceResourceCopyFromJs.variant.qml")
3542 << false // won't be detached, because assigned to property and not explicitly released
3543 << (QStringList() << QLatin1String("scarceResourceCopy"))
3544 << (QList<QVariant>() << true)
3545 << (QList<QVariant>() << origPixmap)
3548 QTest::newRow("variant: import released scarce resource copy from JS")
3549 << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
3551 << true // explicitly released, so it will be detached
3552 << (QStringList() << QLatin1String("scarceResourceCopy"))
3553 << (QList<QVariant>() << false)
3554 << (QList<QVariant>() << QVariant())
3557 // in the following three cases, no other copy should exist in memory,
3558 // and so it should be detached (unless explicitly preserved).
3559 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3560 << testFileUrl("scarceResourceTest.variant.qml")
3562 << true // auto released, so it will be detached
3563 << (QStringList() << QLatin1String("scarceResourceTest"))
3564 << (QList<QVariant>() << true)
3565 << (QList<QVariant>() << QVariant(100))
3567 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3568 << testFileUrl("scarceResourceTestPreserve.variant.qml")
3570 << false // won't be detached because we explicitly preserve it
3571 << (QStringList() << QLatin1String("scarceResourceTest"))
3572 << (QList<QVariant>() << true)
3573 << (QList<QVariant>() << QVariant(100))
3575 QTest::newRow("variant: import multiple scarce resources")
3576 << testFileUrl("scarceResourceTestMultiple.variant.qml")
3578 << true // will be detached because all resources were released manually or automatically.
3579 << (QStringList() << QLatin1String("scarceResourceTest"))
3580 << (QList<QVariant>() << true)
3581 << (QList<QVariant>() << QVariant(100))
3584 // In the following three cases, test that scarce resources are handled
3585 // correctly for imports.
3586 QTest::newRow("variant: import with no binding")
3587 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3588 << false // cannot check detach status.
3591 << QList<QVariant>()
3592 << QList<QVariant>()
3594 QTest::newRow("variant: import with binding without explicit preserve")
3595 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3598 << (QStringList() << QLatin1String("scarceResourceCopy"))
3599 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3600 << (QList<QVariant>() << QVariant())
3602 QTest::newRow("variant: import with explicit release after binding evaluation")
3603 << testFileUrl("scarceResourceCopyImport.variant.qml")
3606 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3607 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3608 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3612 void tst_qdeclarativeecmascript::scarceResources()
3614 QFETCH(QUrl, qmlFile);
3615 QFETCH(bool, readDetachStatus);
3616 QFETCH(bool, expectedDetachStatus);
3617 QFETCH(QStringList, propertyNames);
3618 QFETCH(QVariantList, expectedValidity);
3619 QFETCH(QVariantList, expectedValues);
3620 QFETCH(QStringList, expectedErrors);
3622 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3623 ScarceResourceObject *eo = 0;
3624 QObject *object = 0;
3626 QDeclarativeComponent c(&engine, qmlFile);
3627 object = c.create();
3628 QVERIFY(object != 0);
3629 for (int i = 0; i < propertyNames.size(); ++i) {
3630 QString prop = propertyNames.at(i);
3631 bool validity = expectedValidity.at(i).toBool();
3632 QVariant value = expectedValues.at(i);
3634 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3635 if (value.type() == QVariant::Int) {
3636 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3637 } else if (value.type() == QVariant::Pixmap) {
3638 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3642 if (readDetachStatus) {
3643 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3644 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3647 QVERIFY(ep->scarceResources.isEmpty());
3651 void tst_qdeclarativeecmascript::propertyChangeSlots()
3653 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3654 QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
3655 QObject *object = component.create();
3656 QVERIFY(object != 0);
3659 // ensure that invalid property names fail properly.
3660 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3661 QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
3662 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3663 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3664 object = e1.create();
3665 QVERIFY(object == 0);
3668 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3669 QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
3670 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3671 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3672 object = e2.create();
3673 QVERIFY(object == 0);
3676 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3677 QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
3678 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3679 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3680 object = e3.create();
3681 QVERIFY(object == 0);
3684 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3685 QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
3686 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3687 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3688 object = e4.create();
3689 QVERIFY(object == 0);
3693 void tst_qdeclarativeecmascript::propertyVar_data()
3695 QTest::addColumn<QUrl>("qmlFile");
3698 QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
3699 QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
3700 QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
3701 QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
3702 QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
3703 QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
3704 QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
3705 QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
3706 QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
3707 QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
3710 void tst_qdeclarativeecmascript::propertyVar()
3712 QFETCH(QUrl, qmlFile);
3714 QDeclarativeComponent component(&engine, qmlFile);
3715 QObject *object = component.create();
3716 QVERIFY(object != 0);
3718 QCOMPARE(object->property("test").toBool(), true);
3723 // Tests that we can write QVariant values to var properties from C++
3724 void tst_qdeclarativeecmascript::propertyVarCpp()
3726 QObject *object = 0;
3728 // ensure that writing to and reading from a var property from cpp works as required.
3729 // Literal values stored in var properties can be read and written as QVariants
3730 // of a specific type, whereas object values are read as QVariantMaps.
3731 QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
3732 object = component.create();
3733 QVERIFY(object != 0);
3734 // assign int to property var that currently has int assigned
3735 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3736 QCOMPARE(object->property("varBound"), QVariant(15));
3737 QCOMPARE(object->property("intBound"), QVariant(15));
3738 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3739 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3740 // assign string to property var that current has bool assigned
3741 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3742 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3743 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3744 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3745 // now enforce behaviour when accessing JavaScript objects from cpp.
3746 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3750 static void gc(QDeclarativeEngine &engine)
3752 engine.collectGarbage();
3753 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3756 void tst_qdeclarativeecmascript::propertyVarOwnership()
3758 // Referenced JS objects are not collected
3760 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
3761 QObject *object = component.create();
3762 QVERIFY(object != 0);
3763 QCOMPARE(object->property("test").toBool(), false);
3764 QMetaObject::invokeMethod(object, "runTest");
3765 QCOMPARE(object->property("test").toBool(), true);
3768 // Referenced JS objects are not collected
3770 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
3771 QObject *object = component.create();
3772 QVERIFY(object != 0);
3773 QCOMPARE(object->property("test").toBool(), false);
3774 QMetaObject::invokeMethod(object, "runTest");
3775 QCOMPARE(object->property("test").toBool(), true);
3778 // Qt objects are not collected until they've been dereferenced
3780 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
3781 QObject *object = component.create();
3782 QVERIFY(object != 0);
3784 QCOMPARE(object->property("test2").toBool(), false);
3785 QCOMPARE(object->property("test2").toBool(), false);
3787 QMetaObject::invokeMethod(object, "runTest");
3788 QCOMPARE(object->property("test1").toBool(), true);
3790 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3791 QVERIFY(!referencedObject.isNull());
3793 QVERIFY(!referencedObject.isNull());
3795 QMetaObject::invokeMethod(object, "runTest2");
3796 QCOMPARE(object->property("test2").toBool(), true);
3798 QVERIFY(referencedObject.isNull());
3802 // Self reference does not prevent Qt object collection
3804 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
3805 QObject *object = component.create();
3806 QVERIFY(object != 0);
3808 QCOMPARE(object->property("test").toBool(), true);
3810 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3811 QVERIFY(!referencedObject.isNull());
3813 QVERIFY(!referencedObject.isNull());
3815 QMetaObject::invokeMethod(object, "runTest");
3817 QVERIFY(referencedObject.isNull());
3823 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3825 // The childObject has a reference to a different QObject. We want to ensure
3826 // that the different item will not be cleaned up until required. IE, the childObject
3827 // has implicit ownership of the constructed QObject.
3828 QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
3829 QObject *object = component.create();
3830 QVERIFY(object != 0);
3831 QMetaObject::invokeMethod(object, "assignCircular");
3832 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3833 QObject *rootObject = object->property("vp").value<QObject*>();
3834 QVERIFY(rootObject != 0);
3835 QObject *childObject = rootObject->findChild<QObject*>("text");
3836 QVERIFY(childObject != 0);
3837 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3838 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3839 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3840 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3841 QVERIFY(!qobjectGuard.isNull());
3842 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3843 QVERIFY(!qobjectGuard.isNull());
3844 QMetaObject::invokeMethod(object, "deassignCircular");
3845 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3846 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3850 void tst_qdeclarativeecmascript::propertyVarReparent()
3852 // ensure that nothing breaks if we re-parent objects
3853 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3854 QObject *object = component.create();
3855 QVERIFY(object != 0);
3856 QMetaObject::invokeMethod(object, "assignVarProp");
3857 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3858 QObject *rect = object->property("vp").value<QObject*>();
3859 QObject *text = rect->findChild<QObject*>("textOne");
3860 QObject *text2 = rect->findChild<QObject*>("textTwo");
3861 QWeakPointer<QObject> rectGuard(rect);
3862 QWeakPointer<QObject> textGuard(text);
3863 QWeakPointer<QObject> text2Guard(text2);
3864 QVERIFY(!rectGuard.isNull());
3865 QVERIFY(!textGuard.isNull());
3866 QVERIFY(!text2Guard.isNull());
3867 QCOMPARE(text->property("textCanary").toInt(), 11);
3868 QCOMPARE(text2->property("textCanary").toInt(), 12);
3869 // now construct an image which we will reparent.
3870 QMetaObject::invokeMethod(text2, "constructQObject");
3871 QObject *image = text2->property("vp").value<QObject*>();
3872 QWeakPointer<QObject> imageGuard(image);
3873 QVERIFY(!imageGuard.isNull());
3874 QCOMPARE(image->property("imageCanary").toInt(), 13);
3875 // now reparent the "Image" object (currently, it has JS ownership)
3876 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3877 QMetaObject::invokeMethod(text2, "deassignVp");
3878 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3879 QCOMPARE(text->property("textCanary").toInt(), 11);
3880 QCOMPARE(text2->property("textCanary").toInt(), 22);
3881 QVERIFY(!imageGuard.isNull()); // should still be alive.
3882 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3883 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3884 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3885 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3889 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3891 // sometimes reparenting can cause problems
3892 // (eg, if the ctxt is collected, varproperties are no longer available)
3893 // this test ensures that no crash occurs in that situation.
3894 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3895 QObject *object = component.create();
3896 QVERIFY(object != 0);
3897 QMetaObject::invokeMethod(object, "assignVarProp");
3898 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3899 QObject *rect = object->property("vp").value<QObject*>();
3900 QObject *text = rect->findChild<QObject*>("textOne");
3901 QObject *text2 = rect->findChild<QObject*>("textTwo");
3902 QWeakPointer<QObject> rectGuard(rect);
3903 QWeakPointer<QObject> textGuard(text);
3904 QWeakPointer<QObject> text2Guard(text2);
3905 QVERIFY(!rectGuard.isNull());
3906 QVERIFY(!textGuard.isNull());
3907 QVERIFY(!text2Guard.isNull());
3908 QCOMPARE(text->property("textCanary").toInt(), 11);
3909 QCOMPARE(text2->property("textCanary").toInt(), 12);
3910 // now construct an image which we will reparent.
3911 QMetaObject::invokeMethod(text2, "constructQObject");
3912 QObject *image = text2->property("vp").value<QObject*>();
3913 QWeakPointer<QObject> imageGuard(image);
3914 QVERIFY(!imageGuard.isNull());
3915 QCOMPARE(image->property("imageCanary").toInt(), 13);
3916 // now reparent the "Image" object (currently, it has JS ownership)
3917 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3918 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3919 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3920 QVERIFY(!imageGuard.isNull()); // should still be alive.
3921 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3923 QVERIFY(imageGuard.isNull()); // should now be dead.
3926 void tst_qdeclarativeecmascript::propertyVarCircular()
3928 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3929 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
3930 QObject *object = component.create();
3931 QVERIFY(object != 0);
3932 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3933 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3934 QCOMPARE(object->property("canaryInt"), QVariant(5));
3935 QVariant canaryResourceVariant = object->property("canaryResource");
3936 QVERIFY(canaryResourceVariant.isValid());
3937 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3938 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3939 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3940 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3941 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3942 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3943 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3944 QCOMPARE(object->property("canaryInt"), QVariant(2));
3945 QCOMPARE(object->property("canaryResource"), QVariant(1));
3946 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3950 void tst_qdeclarativeecmascript::propertyVarCircular2()
3952 // track deletion of JS-owned parent item with Cpp-owned child
3953 // where the child has a var property referencing its parent.
3954 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
3955 QObject *object = component.create();
3956 QVERIFY(object != 0);
3957 QMetaObject::invokeMethod(object, "assignCircular");
3958 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3959 QObject *rootObject = object->property("vp").value<QObject*>();
3960 QVERIFY(rootObject != 0);
3961 QObject *childObject = rootObject->findChild<QObject*>("text");
3962 QVERIFY(childObject != 0);
3963 QWeakPointer<QObject> rootObjectTracker(rootObject);
3964 QVERIFY(!rootObjectTracker.isNull());
3965 QWeakPointer<QObject> childObjectTracker(childObject);
3966 QVERIFY(!childObjectTracker.isNull());
3968 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3969 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3970 QMetaObject::invokeMethod(object, "deassignCircular");
3971 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3972 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3973 QVERIFY(childObjectTracker.isNull()); // should have been collected
3977 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3979 *(int*)(parameter) += 1;
3980 qPersistentDispose(object);
3983 void tst_qdeclarativeecmascript::propertyVarInheritance()
3985 int propertyVarWeakRefCallbackCount = 0;
3987 // enforce behaviour regarding element inheritance - ensure handle disposal.
3988 // The particular component under test here has a chain of references.
3989 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
3990 QObject *object = component.create();
3991 QVERIFY(object != 0);
3992 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3993 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3994 // we want to be able to track when the varProperties array of the last metaobject is disposed
3995 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3996 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*>();
3997 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3998 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3999 v8::Persistent<v8::Value> icoCanaryHandle;
4000 v8::Persistent<v8::Value> ccoCanaryHandle;
4003 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4004 // public function which can return us a handle to something in the varProperties array.
4005 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4006 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4007 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4008 // as the varproperties array of each vmemo still references the resource.
4009 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4010 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4012 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4014 // now we deassign the var prop, which should trigger collection of item subtrees.
4015 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4016 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4017 // ensure that there are only weak handles to the underlying varProperties array remaining.
4019 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4021 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4022 // to what remains are weak, all varProperties arrays must have been collected.
4025 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4027 int propertyVarWeakRefCallbackCount = 0;
4029 // The particular component under test here does NOT have a chain of references; the
4030 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4031 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4032 QObject *object = component.create();
4033 QVERIFY(object != 0);
4034 QMetaObject::invokeMethod(object, "assignCircular");
4035 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4036 QObject *rootObject = object->property("vp").value<QObject*>();
4037 QVERIFY(rootObject != 0);
4038 QObject *childObject = rootObject->findChild<QObject*>("text");
4039 QVERIFY(childObject != 0);
4040 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4041 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4042 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4045 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4046 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
4047 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4049 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4050 QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
4051 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4053 QMetaObject::invokeMethod(object, "deassignCircular");
4054 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4055 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4059 // Ensure that QObject type conversion works on binding assignment
4060 void tst_qdeclarativeecmascript::elementAssign()
4062 QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
4064 QObject *object = component.create();
4065 QVERIFY(object != 0);
4067 QCOMPARE(object->property("test").toBool(), true);
4073 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4075 QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
4077 QObject *object = component.create();
4078 QVERIFY(object != 0);
4080 QCOMPARE(object->property("test").toBool(), true);
4086 void tst_qdeclarativeecmascript::objectConversion()
4088 QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
4090 QObject *object = component.create();
4091 QVERIFY(object != 0);
4093 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4094 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4101 void tst_qdeclarativeecmascript::booleanConversion()
4103 QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
4105 QObject *object = component.create();
4106 QVERIFY(object != 0);
4108 QCOMPARE(object->property("test_true1").toBool(), true);
4109 QCOMPARE(object->property("test_true2").toBool(), true);
4110 QCOMPARE(object->property("test_true3").toBool(), true);
4111 QCOMPARE(object->property("test_true4").toBool(), true);
4112 QCOMPARE(object->property("test_true5").toBool(), true);
4114 QCOMPARE(object->property("test_false1").toBool(), false);
4115 QCOMPARE(object->property("test_false2").toBool(), false);
4116 QCOMPARE(object->property("test_false3").toBool(), false);
4121 void tst_qdeclarativeecmascript::handleReferenceManagement()
4126 // Linear QObject reference
4127 QDeclarativeEngine hrmEngine;
4128 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
4129 QObject *object = component.create();
4130 QVERIFY(object != 0);
4131 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4132 cro->setEngine(&hrmEngine);
4133 cro->setDtorCount(&dtorCount);
4134 QMetaObject::invokeMethod(object, "createReference");
4136 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4138 hrmEngine.collectGarbage();
4139 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4140 QCOMPARE(dtorCount, 3);
4145 // Circular QObject reference
4146 QDeclarativeEngine hrmEngine;
4147 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
4148 QObject *object = component.create();
4149 QVERIFY(object != 0);
4150 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4151 cro->setEngine(&hrmEngine);
4152 cro->setDtorCount(&dtorCount);
4153 QMetaObject::invokeMethod(object, "circularReference");
4155 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4157 hrmEngine.collectGarbage();
4158 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4159 QCOMPARE(dtorCount, 3);
4164 // Linear handle reference
4165 QDeclarativeEngine hrmEngine;
4166 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
4167 QObject *object = component.create();
4168 QVERIFY(object != 0);
4169 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4171 crh->setEngine(&hrmEngine);
4172 crh->setDtorCount(&dtorCount);
4173 QMetaObject::invokeMethod(object, "createReference");
4174 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4175 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4176 QVERIFY(first != 0);
4177 QVERIFY(second != 0);
4178 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4179 // now we have to reparent second and make second owned by JS.
4180 second->setParent(0);
4181 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4183 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4185 hrmEngine.collectGarbage();
4186 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4187 QCOMPARE(dtorCount, 3);
4192 // Circular handle reference
4193 QDeclarativeEngine hrmEngine;
4194 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
4195 QObject *object = component.create();
4196 QVERIFY(object != 0);
4197 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4199 crh->setEngine(&hrmEngine);
4200 crh->setDtorCount(&dtorCount);
4201 QMetaObject::invokeMethod(object, "circularReference");
4202 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4203 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4204 QVERIFY(first != 0);
4205 QVERIFY(second != 0);
4206 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4207 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4208 // now we have to reparent and change ownership.
4209 first->setParent(0);
4210 second->setParent(0);
4211 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4212 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4214 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4216 hrmEngine.collectGarbage();
4217 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4218 QCOMPARE(dtorCount, 3);
4223 // multiple engine interaction - linear reference
4224 QDeclarativeEngine hrmEngine1;
4225 QDeclarativeEngine hrmEngine2;
4226 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4227 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4228 QObject *object1 = component1.create();
4229 QObject *object2 = component2.create();
4230 QVERIFY(object1 != 0);
4231 QVERIFY(object2 != 0);
4232 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4233 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4236 crh1->setEngine(&hrmEngine1);
4237 crh2->setEngine(&hrmEngine2);
4238 crh1->setDtorCount(&dtorCount);
4239 crh2->setDtorCount(&dtorCount);
4240 QMetaObject::invokeMethod(object1, "createReference");
4241 QMetaObject::invokeMethod(object2, "createReference");
4242 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4243 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4244 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4245 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4246 QVERIFY(first1 != 0);
4247 QVERIFY(second1 != 0);
4248 QVERIFY(first2 != 0);
4249 QVERIFY(second2 != 0);
4250 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4251 // now we have to reparent second2 and make second2 owned by JS.
4252 second2->setParent(0);
4253 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4255 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4256 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4259 hrmEngine1.collectGarbage();
4260 hrmEngine2.collectGarbage();
4261 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4262 QCOMPARE(dtorCount, 6);
4267 // multiple engine interaction - circular reference
4268 QDeclarativeEngine hrmEngine1;
4269 QDeclarativeEngine hrmEngine2;
4270 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4271 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4272 QObject *object1 = component1.create();
4273 QObject *object2 = component2.create();
4274 QVERIFY(object1 != 0);
4275 QVERIFY(object2 != 0);
4276 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4277 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4280 crh1->setEngine(&hrmEngine1);
4281 crh2->setEngine(&hrmEngine2);
4282 crh1->setDtorCount(&dtorCount);
4283 crh2->setDtorCount(&dtorCount);
4284 QMetaObject::invokeMethod(object1, "createReference");
4285 QMetaObject::invokeMethod(object2, "createReference");
4286 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4287 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4288 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4289 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4290 QVERIFY(first1 != 0);
4291 QVERIFY(second1 != 0);
4292 QVERIFY(first2 != 0);
4293 QVERIFY(second2 != 0);
4294 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4295 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4296 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4297 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4298 // now we have to reparent and change ownership to JS.
4299 first1->setParent(0);
4300 second1->setParent(0);
4301 first2->setParent(0);
4302 second2->setParent(0);
4303 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4304 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4305 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4306 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4308 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4309 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4312 hrmEngine1.collectGarbage();
4313 hrmEngine2.collectGarbage();
4314 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4315 QCOMPARE(dtorCount, 6);
4320 // multiple engine interaction - linear reference with engine deletion
4321 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4322 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4323 QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4324 QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4325 QObject *object1 = component1.create();
4326 QObject *object2 = component2.create();
4327 QVERIFY(object1 != 0);
4328 QVERIFY(object2 != 0);
4329 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4330 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4333 crh1->setEngine(hrmEngine1);
4334 crh2->setEngine(hrmEngine2);
4335 crh1->setDtorCount(&dtorCount);
4336 crh2->setDtorCount(&dtorCount);
4337 QMetaObject::invokeMethod(object1, "createReference");
4338 QMetaObject::invokeMethod(object2, "createReference");
4339 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4340 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4341 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4342 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4343 QVERIFY(first1 != 0);
4344 QVERIFY(second1 != 0);
4345 QVERIFY(first2 != 0);
4346 QVERIFY(second2 != 0);
4347 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4348 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4349 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4350 // now we have to reparent and change ownership to JS.
4351 first1->setParent(crh1);
4352 second1->setParent(0);
4353 first2->setParent(0);
4354 second2->setParent(0);
4355 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4356 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4357 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4359 QCOMPARE(dtorCount, 0);
4362 QCOMPARE(dtorCount, 0);
4365 hrmEngine1->collectGarbage();
4366 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4367 QCOMPARE(dtorCount, 6);
4372 void tst_qdeclarativeecmascript::stringArg()
4374 QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
4375 QObject *object = component.create();
4376 QVERIFY(object != 0);
4377 QMetaObject::invokeMethod(object, "success");
4378 QVERIFY(object->property("returnValue").toBool());
4380 QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4381 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4382 QMetaObject::invokeMethod(object, "failure");
4383 QVERIFY(object->property("returnValue").toBool());
4388 void tst_qdeclarativeecmascript::readonlyDeclaration()
4390 QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
4392 QObject *object = component.create();
4393 QVERIFY(object != 0);
4395 QCOMPARE(object->property("test").toBool(), true);
4400 Q_DECLARE_METATYPE(QList<int>)
4401 Q_DECLARE_METATYPE(QList<qreal>)
4402 Q_DECLARE_METATYPE(QList<bool>)
4403 Q_DECLARE_METATYPE(QList<QString>)
4404 Q_DECLARE_METATYPE(QList<QUrl>)
4405 void tst_qdeclarativeecmascript::sequenceConversionRead()
4408 QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
4409 QDeclarativeComponent component(&engine, qmlFile);
4410 QObject *object = component.create();
4411 QVERIFY(object != 0);
4412 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4415 QMetaObject::invokeMethod(object, "readSequences");
4416 QList<int> intList; intList << 1 << 2 << 3 << 4;
4417 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4418 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4419 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4420 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4421 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4422 QList<bool> boolList; boolList << true << false << true << false;
4423 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4424 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4425 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4426 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4427 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4428 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4429 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4430 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4431 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4432 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4433 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4435 QMetaObject::invokeMethod(object, "readSequenceElements");
4436 QCOMPARE(object->property("intVal").toInt(), 2);
4437 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4438 QCOMPARE(object->property("boolVal").toBool(), false);
4439 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4440 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4441 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4443 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4444 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4446 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4447 QDeclarativeProperty seqProp(seq, "intListProperty");
4448 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4449 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4450 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4452 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4453 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4459 QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
4460 QDeclarativeComponent component(&engine, qmlFile);
4461 QObject *object = component.create();
4462 QVERIFY(object != 0);
4463 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4466 // we haven't registered QList<QPoint> as a sequence type.
4467 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4468 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4469 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4470 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4472 QMetaObject::invokeMethod(object, "performTest");
4474 // QList<QPoint> has not been registered as a sequence type.
4475 QCOMPARE(object->property("pointListLength").toInt(), 0);
4476 QVERIFY(!object->property("pointList").isValid());
4477 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4478 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4479 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4485 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4488 QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
4489 QDeclarativeComponent component(&engine, qmlFile);
4490 QObject *object = component.create();
4491 QVERIFY(object != 0);
4492 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4495 QMetaObject::invokeMethod(object, "writeSequences");
4496 QCOMPARE(object->property("success").toBool(), true);
4498 QMetaObject::invokeMethod(object, "writeSequenceElements");
4499 QCOMPARE(object->property("success").toBool(), true);
4501 QMetaObject::invokeMethod(object, "writeOtherElements");
4502 QCOMPARE(object->property("success").toBool(), true);
4504 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4505 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4511 QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
4512 QDeclarativeComponent component(&engine, qmlFile);
4513 QObject *object = component.create();
4514 QVERIFY(object != 0);
4515 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4518 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4519 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4520 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4522 QMetaObject::invokeMethod(object, "performTest");
4524 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4525 QCOMPARE(seq->pointListProperty(), pointList);
4531 void tst_qdeclarativeecmascript::sequenceConversionArray()
4533 // ensure that in JS the returned sequences act just like normal JS Arrays.
4534 QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
4535 QDeclarativeComponent component(&engine, qmlFile);
4536 QObject *object = component.create();
4537 QVERIFY(object != 0);
4538 QMetaObject::invokeMethod(object, "indexedAccess");
4539 QVERIFY(object->property("success").toBool());
4540 QMetaObject::invokeMethod(object, "arrayOperations");
4541 QVERIFY(object->property("success").toBool());
4542 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4543 QVERIFY(object->property("success").toBool());
4544 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4545 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4549 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4551 // ensure that sequence conversion operations work correctly in a worker thread
4552 // and that serialisation between the main and worker thread succeeds.
4553 QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
4554 QDeclarativeComponent component(&engine, qmlFile);
4555 QObject *object = component.create();
4556 QVERIFY(object != 0);
4558 QMetaObject::invokeMethod(object, "testIntSequence");
4559 QTRY_VERIFY(object->property("finished").toBool());
4560 QVERIFY(object->property("success").toBool());
4562 QMetaObject::invokeMethod(object, "testQrealSequence");
4563 QTRY_VERIFY(object->property("finished").toBool());
4564 QVERIFY(object->property("success").toBool());
4566 QMetaObject::invokeMethod(object, "testBoolSequence");
4567 QTRY_VERIFY(object->property("finished").toBool());
4568 QVERIFY(object->property("success").toBool());
4570 QMetaObject::invokeMethod(object, "testStringSequence");
4571 QTRY_VERIFY(object->property("finished").toBool());
4572 QVERIFY(object->property("success").toBool());
4574 QMetaObject::invokeMethod(object, "testQStringSequence");
4575 QTRY_VERIFY(object->property("finished").toBool());
4576 QVERIFY(object->property("success").toBool());
4578 QMetaObject::invokeMethod(object, "testUrlSequence");
4579 QTRY_VERIFY(object->property("finished").toBool());
4580 QVERIFY(object->property("success").toBool());
4582 QMetaObject::invokeMethod(object, "testVariantSequence");
4583 QTRY_VERIFY(object->property("finished").toBool());
4584 QVERIFY(object->property("success").toBool());
4589 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4592 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
4593 QDeclarativeComponent component(&engine, qmlFile);
4594 QObject *object = component.create();
4595 QVERIFY(object != 0);
4596 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4597 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4598 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4599 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4600 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4605 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
4606 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4607 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4608 QDeclarativeComponent component(&engine, qmlFile);
4609 QObject *object = component.create();
4610 QVERIFY(object != 0);
4615 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4617 QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
4618 QDeclarativeComponent component(&engine, qmlFile);
4619 QObject *object = component.create();
4620 QVERIFY(object != 0);
4621 QMetaObject::invokeMethod(object, "testCopySequences");
4622 QCOMPARE(object->property("success").toBool(), true);
4623 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4624 QCOMPARE(object->property("success").toBool(), true);
4625 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4626 QCOMPARE(object->property("success").toBool(), true);
4630 void tst_qdeclarativeecmascript::assignSequenceTypes()
4632 // test binding array to sequence type property
4634 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
4635 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4636 QVERIFY(object != 0);
4637 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4638 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4639 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4640 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4641 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4642 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4646 // test binding literal to sequence type property
4648 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
4649 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4650 QVERIFY(object != 0);
4651 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4652 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4653 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4654 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4655 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4656 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4660 // test binding single value to sequence type property
4662 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
4663 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4664 QVERIFY(object != 0);
4665 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4666 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4667 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4668 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4672 // test assigning array to sequence type property in js function
4674 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
4675 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4676 QVERIFY(object != 0);
4677 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4678 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4679 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4680 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4681 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4682 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4686 // test assigning literal to sequence type property in js function
4688 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
4689 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4690 QVERIFY(object != 0);
4691 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4692 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4693 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4694 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4695 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4696 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4700 // test assigning single value to sequence type property in js function
4702 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
4703 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4704 QVERIFY(object != 0);
4705 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4706 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4707 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4708 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4712 // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
4714 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
4715 QObject *object = component.create();
4716 QVERIFY(object != 0);
4717 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
4718 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
4719 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
4720 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
4721 MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
4722 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
4723 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4724 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4725 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4726 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4727 QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4732 // Test that assigning a null object works
4733 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4734 void tst_qdeclarativeecmascript::nullObjectBinding()
4736 QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
4738 QObject *object = component.create();
4739 QVERIFY(object != 0);
4741 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4746 // Test that bindings don't evaluate once the engine has been destroyed
4747 void tst_qdeclarativeecmascript::deletedEngine()
4749 QDeclarativeEngine *engine = new QDeclarativeEngine;
4750 QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
4752 QObject *object = component.create();
4753 QVERIFY(object != 0);
4755 QCOMPARE(object->property("a").toInt(), 39);
4756 object->setProperty("b", QVariant(9));
4757 QCOMPARE(object->property("a").toInt(), 117);
4761 QCOMPARE(object->property("a").toInt(), 117);
4762 object->setProperty("b", QVariant(10));
4763 QCOMPARE(object->property("a").toInt(), 117);
4768 // Test the crashing part of QTBUG-9705
4769 void tst_qdeclarativeecmascript::libraryScriptAssert()
4771 QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
4773 QObject *object = component.create();
4774 QVERIFY(object != 0);
4779 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4781 QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
4783 QObject *object = component.create();
4784 QVERIFY(object != 0);
4786 QCOMPARE(object->property("test1").toInt(), 10);
4787 QCOMPARE(object->property("test2").toInt(), 11);
4789 object->setProperty("runTest", true);
4791 QCOMPARE(object->property("test1"), QVariant());
4792 QCOMPARE(object->property("test2"), QVariant());
4798 void tst_qdeclarativeecmascript::qtbug_9792()
4800 QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
4802 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4804 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4805 QVERIFY(object != 0);
4807 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4808 object->basicSignal();
4812 transientErrorsMsgCount = 0;
4813 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4815 object->basicSignal();
4817 qInstallMsgHandler(old);
4819 QCOMPARE(transientErrorsMsgCount, 0);
4824 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4825 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4827 QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
4829 QObject *o = component.create();
4832 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4833 QVERIFY(nested != 0);
4835 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4838 nested = qvariant_cast<QObject *>(o->property("object"));
4839 QVERIFY(nested == 0);
4841 // If the bug is present, the next line will crash
4845 // Test that we shut down without stupid warnings
4846 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4849 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
4851 QObject *o = component.create();
4853 transientErrorsMsgCount = 0;
4854 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4858 qInstallMsgHandler(old);
4860 QCOMPARE(transientErrorsMsgCount, 0);
4865 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
4867 QObject *o = component.create();
4869 transientErrorsMsgCount = 0;
4870 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4874 qInstallMsgHandler(old);
4876 QCOMPARE(transientErrorsMsgCount, 0);
4880 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4883 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
4885 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4888 QVERIFY(o->objectProperty() != 0);
4890 o->setProperty("runTest", true);
4892 QVERIFY(o->objectProperty() == 0);
4898 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
4900 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4903 QVERIFY(o->objectProperty() == 0);
4909 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4911 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
4913 QString url = component.url().toString();
4914 QString warning = url + ":4: Unable to assign a function to a property.";
4915 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4917 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4920 QVERIFY(!o->property("a").isValid());
4925 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4927 QFETCH(QString, triggerProperty);
4929 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4930 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4932 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4934 QVERIFY(!o->property("a").isValid());
4936 o->setProperty("aNumber", QVariant(5));
4937 o->setProperty(triggerProperty.toUtf8().constData(), true);
4938 QCOMPARE(o->property("a"), QVariant(50));
4940 o->setProperty("aNumber", QVariant(10));
4941 QCOMPARE(o->property("a"), QVariant(100));
4946 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4948 QTest::addColumn<QString>("triggerProperty");
4950 QTest::newRow("assign to property") << "assignToProperty";
4951 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4953 QTest::newRow("assign to value type") << "assignToValueType";
4955 QTest::newRow("use 'this'") << "assignWithThis";
4956 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4959 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4961 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4962 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4964 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4966 QVERIFY(!o->property("a").isValid());
4968 o->setProperty("assignFuncWithoutReturn", true);
4969 QVERIFY(!o->property("a").isValid());
4971 QString url = component.url().toString();
4972 QString warning = url + ":67: Unable to assign QString to int";
4973 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4974 o->setProperty("assignWrongType", true);
4976 warning = url + ":71: Unable to assign QString to int";
4977 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4978 o->setProperty("assignWrongTypeToValueType", true);
4983 void tst_qdeclarativeecmascript::eval()
4985 QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
4987 QObject *o = component.create();
4990 QCOMPARE(o->property("test1").toBool(), true);
4991 QCOMPARE(o->property("test2").toBool(), true);
4992 QCOMPARE(o->property("test3").toBool(), true);
4993 QCOMPARE(o->property("test4").toBool(), true);
4994 QCOMPARE(o->property("test5").toBool(), true);
4999 void tst_qdeclarativeecmascript::function()
5001 QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
5003 QObject *o = component.create();
5006 QCOMPARE(o->property("test1").toBool(), true);
5007 QCOMPARE(o->property("test2").toBool(), true);
5008 QCOMPARE(o->property("test3").toBool(), true);
5013 // Test the "Qt.include" method
5014 void tst_qdeclarativeecmascript::include()
5016 // Non-library relative include
5018 QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
5019 QObject *o = component.create();
5022 QCOMPARE(o->property("test0").toInt(), 99);
5023 QCOMPARE(o->property("test1").toBool(), true);
5024 QCOMPARE(o->property("test2").toBool(), true);
5025 QCOMPARE(o->property("test2_1").toBool(), true);
5026 QCOMPARE(o->property("test3").toBool(), true);
5027 QCOMPARE(o->property("test3_1").toBool(), true);
5032 // Library relative include
5034 QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
5035 QObject *o = component.create();
5038 QCOMPARE(o->property("test0").toInt(), 99);
5039 QCOMPARE(o->property("test1").toBool(), true);
5040 QCOMPARE(o->property("test2").toBool(), true);
5041 QCOMPARE(o->property("test2_1").toBool(), true);
5042 QCOMPARE(o->property("test3").toBool(), true);
5043 QCOMPARE(o->property("test3_1").toBool(), true);
5050 QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
5051 QObject *o = component.create();
5054 QCOMPARE(o->property("test1").toBool(), true);
5055 QCOMPARE(o->property("test2").toBool(), true);
5056 QCOMPARE(o->property("test3").toBool(), true);
5057 QCOMPARE(o->property("test4").toBool(), true);
5058 QCOMPARE(o->property("test5").toBool(), true);
5059 QCOMPARE(o->property("test6").toBool(), true);
5064 // Including file with ".pragma library"
5066 QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
5067 QObject *o = component.create();
5069 QCOMPARE(o->property("test1").toInt(), 100);
5076 TestHTTPServer server(8111);
5077 QVERIFY(server.isValid());
5078 server.serveDirectory(dataDirectory());
5080 QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
5081 QObject *o = component.create();
5084 QTRY_VERIFY(o->property("done").toBool() == true);
5085 QTRY_VERIFY(o->property("done2").toBool() == true);
5087 QCOMPARE(o->property("test1").toBool(), true);
5088 QCOMPARE(o->property("test2").toBool(), true);
5089 QCOMPARE(o->property("test3").toBool(), true);
5090 QCOMPARE(o->property("test4").toBool(), true);
5091 QCOMPARE(o->property("test5").toBool(), true);
5093 QCOMPARE(o->property("test6").toBool(), true);
5094 QCOMPARE(o->property("test7").toBool(), true);
5095 QCOMPARE(o->property("test8").toBool(), true);
5096 QCOMPARE(o->property("test9").toBool(), true);
5097 QCOMPARE(o->property("test10").toBool(), true);
5104 TestHTTPServer server(8111);
5105 QVERIFY(server.isValid());
5106 server.serveDirectory(dataDirectory());
5108 QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
5109 QObject *o = component.create();
5112 QTRY_VERIFY(o->property("done").toBool() == true);
5114 QCOMPARE(o->property("test1").toBool(), true);
5115 QCOMPARE(o->property("test2").toBool(), true);
5116 QCOMPARE(o->property("test3").toBool(), true);
5122 void tst_qdeclarativeecmascript::signalHandlers()
5124 QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
5125 QObject *o = component.create();
5128 QVERIFY(o->property("count").toInt() == 0);
5129 QMetaObject::invokeMethod(o, "testSignalCall");
5130 QCOMPARE(o->property("count").toInt(), 1);
5132 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5133 QCOMPARE(o->property("count").toInt(), 1);
5134 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5136 QVERIFY(o->property("funcCount").toInt() == 0);
5137 QMetaObject::invokeMethod(o, "testSignalConnection");
5138 QCOMPARE(o->property("funcCount").toInt(), 1);
5140 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5141 QCOMPARE(o->property("funcCount").toInt(), 2);
5143 QMetaObject::invokeMethod(o, "testSignalDefined");
5144 QCOMPARE(o->property("definedResult").toBool(), true);
5146 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5147 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5152 void tst_qdeclarativeecmascript::qtbug_10696()
5154 QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
5155 QObject *o = component.create();
5160 void tst_qdeclarativeecmascript::qtbug_11606()
5162 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
5163 QObject *o = component.create();
5165 QCOMPARE(o->property("test").toBool(), true);
5169 void tst_qdeclarativeecmascript::qtbug_11600()
5171 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
5172 QObject *o = component.create();
5174 QCOMPARE(o->property("test").toBool(), true);
5178 void tst_qdeclarativeecmascript::qtbug_21864()
5180 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
5181 QObject *o = component.create();
5183 QCOMPARE(o->property("test").toBool(), true);
5187 void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
5190 QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
5191 QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
5192 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5193 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5194 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5195 QObject *o = component.create();
5197 QCOMPARE(o->property("test").toBool(), true);
5201 // Reading and writing non-scriptable properties should fail
5202 void tst_qdeclarativeecmascript::nonscriptable()
5204 QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
5205 QObject *o = component.create();
5207 QCOMPARE(o->property("readOk").toBool(), true);
5208 QCOMPARE(o->property("writeOk").toBool(), true);
5212 // deleteLater() should not be callable from QML
5213 void tst_qdeclarativeecmascript::deleteLater()
5215 QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
5216 QObject *o = component.create();
5218 QCOMPARE(o->property("test").toBool(), true);
5222 void tst_qdeclarativeecmascript::in()
5224 QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
5225 QObject *o = component.create();
5227 QCOMPARE(o->property("test1").toBool(), true);
5228 QCOMPARE(o->property("test2").toBool(), true);
5232 void tst_qdeclarativeecmascript::typeOf()
5234 QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
5236 // These warnings should not happen once QTBUG-21864 is fixed
5237 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5238 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5240 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5241 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5243 QObject *o = component.create();
5246 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5247 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5248 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5249 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5250 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5251 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5252 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5253 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5254 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5255 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5260 void tst_qdeclarativeecmascript::sharedAttachedObject()
5262 QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
5263 QObject *o = component.create();
5265 QCOMPARE(o->property("test1").toBool(), true);
5266 QCOMPARE(o->property("test2").toBool(), true);
5271 void tst_qdeclarativeecmascript::objectName()
5273 QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
5274 QObject *o = component.create();
5277 QCOMPARE(o->property("test1").toString(), QString("hello"));
5278 QCOMPARE(o->property("test2").toString(), QString("ell"));
5280 o->setObjectName("world");
5282 QCOMPARE(o->property("test1").toString(), QString("world"));
5283 QCOMPARE(o->property("test2").toString(), QString("orl"));
5288 void tst_qdeclarativeecmascript::writeRemovesBinding()
5290 QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
5291 QObject *o = component.create();
5294 QCOMPARE(o->property("test").toBool(), true);
5299 // Test bindings assigned to alias properties actually assign to the alias' target
5300 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5302 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
5303 QObject *o = component.create();
5306 QCOMPARE(o->property("test").toBool(), true);
5311 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5312 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5315 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
5316 QObject *o = component.create();
5319 QCOMPARE(o->property("test").toBool(), true);
5325 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
5326 QObject *o = component.create();
5329 QCOMPARE(o->property("test").toBool(), true);
5335 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
5336 QObject *o = component.create();
5339 QCOMPARE(o->property("test").toBool(), true);
5345 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5346 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5349 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
5350 QObject *o = component.create();
5353 QCOMPARE(o->property("test").toBool(), true);
5359 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
5360 QObject *o = component.create();
5363 QCOMPARE(o->property("test").toBool(), true);
5369 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
5370 QObject *o = component.create();
5373 QCOMPARE(o->property("test").toBool(), true);
5379 // Allow an alais to a composite element
5381 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5383 QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
5385 QObject *object = component.create();
5386 QVERIFY(object != 0);
5391 void tst_qdeclarativeecmascript::qtbug_20344()
5393 QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
5395 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5396 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5398 QObject *object = component.create();
5399 QVERIFY(object != 0);
5404 void tst_qdeclarativeecmascript::revisionErrors()
5407 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
5408 QString url = component.url().toString();
5410 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5411 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5412 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5414 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5415 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5416 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5417 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5418 QVERIFY(object != 0);
5422 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
5423 QString url = component.url().toString();
5425 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5426 // method2, prop2 from MyRevisionedClass not available
5427 // method4, prop4 from MyRevisionedSubclass not available
5428 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5429 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5430 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5431 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5432 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5434 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5435 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5436 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5437 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5438 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5439 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5440 QVERIFY(object != 0);
5444 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
5445 QString url = component.url().toString();
5447 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5448 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5449 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5450 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5451 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5452 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5453 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5454 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5455 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5456 QVERIFY(object != 0);
5461 void tst_qdeclarativeecmascript::revision()
5464 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
5465 QString url = component.url().toString();
5467 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5468 QVERIFY(object != 0);
5472 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
5473 QString url = component.url().toString();
5475 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5476 QVERIFY(object != 0);
5480 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
5481 QString url = component.url().toString();
5483 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5484 QVERIFY(object != 0);
5487 // Test that non-root classes can resolve revisioned methods
5489 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
5491 QObject *object = component.create();
5492 QVERIFY(object != 0);
5493 QCOMPARE(object->property("test").toReal(), 11.);
5498 void tst_qdeclarativeecmascript::realToInt()
5500 QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
5501 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5502 QVERIFY(object != 0);
5504 QMetaObject::invokeMethod(object, "test1");
5505 QCOMPARE(object->value(), int(4));
5506 QMetaObject::invokeMethod(object, "test2");
5507 QCOMPARE(object->value(), int(8));
5510 void tst_qdeclarativeecmascript::urlProperty()
5513 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
5514 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5515 QVERIFY(object != 0);
5516 object->setStringProperty("http://qt-project.org");
5517 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5518 QCOMPARE(object->intProperty(), 123);
5519 QCOMPARE(object->value(), 1);
5520 QCOMPARE(object->property("result").toBool(), true);
5524 void tst_qdeclarativeecmascript::urlPropertyWithEncoding()
5527 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.2.qml"));
5528 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5529 QVERIFY(object != 0);
5530 object->setStringProperty("http://qt-project.org");
5532 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5533 QCOMPARE(object->urlProperty(), encoded);
5534 QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
5535 QCOMPARE(object->property("result").toBool(), true);
5539 void tst_qdeclarativeecmascript::urlListPropertyWithEncoding()
5542 QDeclarativeComponent component(&engine, testFileUrl("urlListProperty.qml"));
5543 QObject *object = component.create();
5544 QVERIFY(object != 0);
5545 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
5546 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
5547 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
5548 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
5549 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
5551 encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
5552 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
5553 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
5554 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5555 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
5560 void tst_qdeclarativeecmascript::dynamicString()
5562 QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
5563 QObject *object = component.create();
5564 QVERIFY(object != 0);
5565 QCOMPARE(object->property("stringProperty").toString(),
5566 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5569 void tst_qdeclarativeecmascript::automaticSemicolon()
5571 QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
5572 QObject *object = component.create();
5573 QVERIFY(object != 0);
5576 void tst_qdeclarativeecmascript::unaryExpression()
5578 QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
5579 QObject *object = component.create();
5580 QVERIFY(object != 0);
5583 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5584 void tst_qdeclarativeecmascript::doubleEvaluate()
5586 QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
5587 QObject *object = component.create();
5588 QVERIFY(object != 0);
5589 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5591 QCOMPARE(wc->count(), 1);
5593 wc->setProperty("x", 9);
5595 QCOMPARE(wc->count(), 2);
5600 static QStringList messages;
5601 static void captureMsgHandler(QtMsgType, const char *msg)
5603 messages.append(QLatin1String(msg));
5606 void tst_qdeclarativeecmascript::nonNotifyable()
5608 QV4Compiler::enableV4(false);
5609 QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
5610 QV4Compiler::enableV4(true);
5612 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5614 QObject *object = component.create();
5615 qInstallMsgHandler(old);
5617 QVERIFY(object != 0);
5619 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5620 component.url().toString() +
5621 QLatin1String(":5 depends on non-NOTIFYable properties:");
5622 QString expected2 = QLatin1String(" ") +
5623 QLatin1String(object->metaObject()->className()) +
5624 QLatin1String("::value");
5626 QCOMPARE(messages.length(), 2);
5627 QCOMPARE(messages.at(0), expected1);
5628 QCOMPARE(messages.at(1), expected2);
5633 void tst_qdeclarativeecmascript::forInLoop()
5635 QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
5636 QObject *object = component.create();
5637 QVERIFY(object != 0);
5639 QMetaObject::invokeMethod(object, "listProperty");
5641 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5642 QCOMPARE(r.size(), 3);
5643 QCOMPARE(r[0],QLatin1String("0=obj1"));
5644 QCOMPARE(r[1],QLatin1String("1=obj2"));
5645 QCOMPARE(r[2],QLatin1String("2=obj3"));
5647 //TODO: should test for in loop for other objects (such as QObjects) as well.
5652 // An object the binding depends on is deleted while the binding is still running
5653 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5655 QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
5656 QObject *object = component.create();
5657 QVERIFY(object != 0);
5661 void tst_qdeclarativeecmascript::qtbug_22679()
5664 object.setStringProperty(QLatin1String("Please work correctly"));
5665 engine.rootContext()->setContextProperty("contextProp", &object);
5667 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
5668 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5669 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5671 QObject *o = component.create();
5673 QCOMPARE(warningsSpy.count(), 0);
5677 void tst_qdeclarativeecmascript::qtbug_22843_data()
5679 QTest::addColumn<bool>("library");
5681 QTest::newRow("without .pragma library") << false;
5682 QTest::newRow("with .pragma library") << true;
5685 void tst_qdeclarativeecmascript::qtbug_22843()
5687 QFETCH(bool, library);
5689 QString fileName("qtbug_22843");
5691 fileName += QLatin1String(".library");
5692 fileName += QLatin1String(".qml");
5694 QDeclarativeComponent component(&engine, testFileUrl(fileName));
5695 QString url = component.url().toString();
5696 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5697 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5699 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5700 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5701 for (int x = 0; x < 3; ++x) {
5702 warningsSpy.clear();
5703 // For libraries, only the first import attempt should produce a
5704 // SyntaxError warning; subsequent component creation should not
5705 // attempt to reload the script.
5706 bool expectSyntaxError = !library || (x == 0);
5707 if (expectSyntaxError)
5708 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5709 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5710 QObject *object = component.create();
5711 QVERIFY(object != 0);
5712 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5718 void tst_qdeclarativeecmascript::switchStatement()
5721 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
5722 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5723 QVERIFY(object != 0);
5725 // `object->value()' is the number of executed statements
5727 object->setStringProperty("A");
5728 QCOMPARE(object->value(), 5);
5730 object->setStringProperty("S");
5731 QCOMPARE(object->value(), 3);
5733 object->setStringProperty("D");
5734 QCOMPARE(object->value(), 3);
5736 object->setStringProperty("F");
5737 QCOMPARE(object->value(), 4);
5739 object->setStringProperty("something else");
5740 QCOMPARE(object->value(), 1);
5744 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
5745 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5746 QVERIFY(object != 0);
5748 // `object->value()' is the number of executed statements
5750 object->setStringProperty("A");
5751 QCOMPARE(object->value(), 5);
5753 object->setStringProperty("S");
5754 QCOMPARE(object->value(), 3);
5756 object->setStringProperty("D");
5757 QCOMPARE(object->value(), 3);
5759 object->setStringProperty("F");
5760 QCOMPARE(object->value(), 3);
5762 object->setStringProperty("something else");
5763 QCOMPARE(object->value(), 4);
5767 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
5768 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5769 QVERIFY(object != 0);
5771 // `object->value()' is the number of executed statements
5773 object->setStringProperty("A");
5774 QCOMPARE(object->value(), 5);
5776 object->setStringProperty("S");
5777 QCOMPARE(object->value(), 3);
5779 object->setStringProperty("D");
5780 QCOMPARE(object->value(), 3);
5782 object->setStringProperty("F");
5783 QCOMPARE(object->value(), 3);
5785 object->setStringProperty("something else");
5786 QCOMPARE(object->value(), 6);
5790 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
5792 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5793 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5795 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5796 QVERIFY(object != 0);
5798 // `object->value()' is the number of executed statements
5800 object->setStringProperty("A");
5801 QCOMPARE(object->value(), 5);
5803 object->setStringProperty("S");
5804 QCOMPARE(object->value(), 3);
5806 object->setStringProperty("D");
5807 QCOMPARE(object->value(), 3);
5809 object->setStringProperty("F");
5810 QCOMPARE(object->value(), 3);
5812 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5814 object->setStringProperty("something else");
5818 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
5819 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5820 QVERIFY(object != 0);
5822 // `object->value()' is the number of executed statements
5824 object->setStringProperty("A");
5825 QCOMPARE(object->value(), 1);
5827 object->setStringProperty("S");
5828 QCOMPARE(object->value(), 1);
5830 object->setStringProperty("D");
5831 QCOMPARE(object->value(), 1);
5833 object->setStringProperty("F");
5834 QCOMPARE(object->value(), 1);
5836 object->setStringProperty("something else");
5837 QCOMPARE(object->value(), 1);
5841 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
5842 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5843 QVERIFY(object != 0);
5845 // `object->value()' is the number of executed statements
5847 object->setStringProperty("A");
5848 QCOMPARE(object->value(), 123);
5850 object->setStringProperty("S");
5851 QCOMPARE(object->value(), 123);
5853 object->setStringProperty("D");
5854 QCOMPARE(object->value(), 321);
5856 object->setStringProperty("F");
5857 QCOMPARE(object->value(), 321);
5859 object->setStringProperty("something else");
5860 QCOMPARE(object->value(), 0);
5864 void tst_qdeclarativeecmascript::withStatement()
5867 QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
5868 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5869 QVERIFY(object != 0);
5871 QCOMPARE(object->value(), 123);
5875 void tst_qdeclarativeecmascript::tryStatement()
5878 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
5879 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5880 QVERIFY(object != 0);
5882 QCOMPARE(object->value(), 123);
5886 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
5887 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5888 QVERIFY(object != 0);
5890 QCOMPARE(object->value(), 321);
5894 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
5895 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5896 QVERIFY(object != 0);
5898 QCOMPARE(object->value(), 1);
5902 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
5903 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5904 QVERIFY(object != 0);
5906 QCOMPARE(object->value(), 1);
5910 QTEST_MAIN(tst_qdeclarativeecmascript)
5912 #include "tst_qdeclarativeecmascript.moc"