1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include <private/qv8gccallback_p.h>
53 #include <private/qdeclarativevmemetaobject_p.h>
54 #include <private/qv4compiler_p.h>
55 #include "testtypes.h"
56 #include "testhttpserver.h"
57 #include "../../shared/util.h"
60 This test covers evaluation of ECMAScript expressions and bindings from within
61 QML. This does not include static QML language issues.
63 Static QML language issues are covered in qmllanguage
65 inline QUrl TEST_FILE(const QString &filename)
67 return QUrl::fromLocalFile(TESTDATA(filename));
70 inline QUrl TEST_FILE(const char *filename)
72 return TEST_FILE(QLatin1String(filename));
75 class tst_qdeclarativeecmascript : public QObject
79 tst_qdeclarativeecmascript() {}
83 void assignBasicTypes();
84 void idShortcutInvalidates();
85 void boolPropertiesEvaluateAsBool();
87 void signalAssignment();
89 void basicExpressions();
90 void basicExpressions_data();
91 void arrayExpressions();
92 void contextPropertiesTriggerReeval();
93 void objectPropertiesTriggerReeval();
94 void deferredProperties();
95 void deferredPropertiesErrors();
96 void extensionObjects();
97 void overrideExtensionProperties();
98 void attachedProperties();
100 void valueTypeFunctions();
101 void constantsOverrideBindings();
102 void outerBindingOverridesInnerBinding();
103 void aliasPropertyAndBinding();
104 void aliasPropertyReset();
105 void nonExistentAttachedObject();
108 void signalParameterTypes();
109 void objectsCompareAsEqual();
110 void dynamicCreation_data();
111 void dynamicCreation();
112 void dynamicDestruction();
113 void objectToString();
114 void objectHasOwnProperty();
115 void selfDeletingBinding();
116 void extendedObjectPropertyLookup();
117 void extendedObjectPropertyLookup2();
119 void functionErrors();
120 void propertyAssignmentErrors();
121 void signalTriggeredBindings();
122 void listProperties();
123 void exceptionClearsOnReeval();
124 void exceptionSlotProducesWarning();
125 void exceptionBindingProducesWarning();
126 void transientErrors();
127 void shutdownErrors();
128 void compositePropertyType();
130 void undefinedResetsProperty();
131 void listToVariant();
132 void listAssignment();
133 void multiEngineObject();
134 void deletedObject();
135 void attachedPropertyScope();
136 void scriptConnect();
137 void scriptDisconnect();
139 void cppOwnershipReturnValue();
140 void ownershipCustomReturnValue();
141 void qlistqobjectMethods();
142 void strictlyEquals();
144 void numberAssignment();
145 void propertySplicing();
146 void signalWithUnknownTypes();
147 void signalWithJSValueInVariant_data();
148 void signalWithJSValueInVariant();
149 void signalWithJSValueInVariant_twoEngines_data();
150 void signalWithJSValueInVariant_twoEngines();
151 void moduleApi_data();
153 void importScripts_data();
154 void importScripts();
155 void scarceResources();
156 void scarceResources_data();
157 void scarceResources_other();
158 void propertyChangeSlots();
159 void propertyVar_data();
161 void propertyVarCpp();
162 void propertyVarOwnership();
163 void propertyVarImplicitOwnership();
164 void propertyVarReparent();
165 void propertyVarReparentNullContext();
166 void propertyVarCircular();
167 void propertyVarCircular2();
168 void propertyVarInheritance();
169 void propertyVarInheritance2();
170 void elementAssign();
171 void objectPassThroughSignals();
172 void objectConversion();
173 void booleanConversion();
174 void handleReferenceManagement();
176 void readonlyDeclaration();
177 void sequenceConversionRead();
178 void sequenceConversionWrite();
179 void sequenceConversionArray();
180 void sequenceConversionThreads();
181 void sequenceConversionBindings();
182 void sequenceConversionCopy();
183 void assignSequenceTypes();
189 void dynamicCreationCrash();
190 void dynamicCreationOwnership();
192 void nullObjectBinding();
193 void deletedEngine();
194 void libraryScriptAssert();
195 void variantsAssignedUndefined();
197 void qtcreatorbug_1289();
198 void noSpuriousWarningsAtShutdown();
199 void canAssignNullToQObject();
200 void functionAssignment_fromBinding();
201 void functionAssignment_fromJS();
202 void functionAssignment_fromJS_data();
203 void functionAssignmentfromJS_invalid();
210 void nonscriptable();
214 void sharedAttachedObject();
216 void writeRemovesBinding();
217 void aliasBindingsAssignCorrectly();
218 void aliasBindingsOverrideTarget();
219 void aliasWritesOverrideBindings();
220 void aliasToCompositeElement();
222 void dynamicString();
224 void signalHandlers();
225 void doubleEvaluate();
227 void nonNotifyable();
228 void deleteWhileBindingRunning();
229 void callQtInvokables();
230 void invokableObjectArg();
231 void invokableObjectRet();
234 void qtbug_22843_data();
236 void revisionErrors();
239 void automaticSemicolon();
240 void unaryExpression();
241 void switchStatement();
242 void withStatement();
246 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
247 QDeclarativeEngine engine;
250 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
252 void tst_qdeclarativeecmascript::assignBasicTypes()
255 QDeclarativeComponent component(&engine, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("methods.3.qml"));
404 QObject *object = component.create();
405 QVERIFY(object != 0);
406 QCOMPARE(object->property("test").toInt(), 19);
411 QDeclarativeComponent component(&engine, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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 TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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 = TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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 = TEST_FILE("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, TEST_FILE("selfDeletingBinding.qml"));
1334 QObject *object = component.create();
1335 QVERIFY(object != 0);
1336 object->setProperty("triggerDelete", true);
1341 QDeclarativeComponent component(&engine, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("invokableObjectRet.qml"));
2329 QObject *o = component.create();
2331 QCOMPARE(o->property("test").toBool(), true);
2336 void tst_qdeclarativeecmascript::listToVariant()
2338 QDeclarativeComponent component(&engine, TEST_FILE("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, TEST_FILE("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, TEST_FILE("multiEngineObject.qml"));
2380 QDeclarativeEngine e2;
2381 e2.rootContext()->setContextProperty("thing", &obj);
2382 QDeclarativeComponent c2(&e2, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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::moduleApi_data()
2950 QTest::addColumn<QUrl>("testfile");
2951 QTest::addColumn<QString>("errorMessage");
2952 QTest::addColumn<QStringList>("warningMessages");
2953 QTest::addColumn<QStringList>("readProperties");
2954 QTest::addColumn<QVariantList>("readExpectedValues");
2955 QTest::addColumn<QStringList>("writeProperties");
2956 QTest::addColumn<QVariantList>("writeValues");
2957 QTest::addColumn<QStringList>("readBackProperties");
2958 QTest::addColumn<QVariantList>("readBackExpectedValues");
2960 QTest::newRow("qobject, register + read + method")
2961 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2964 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2965 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2966 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2972 QTest::newRow("script, register + read")
2973 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2976 << (QStringList() << "scriptTest")
2977 << (QVariantList() << 13)
2983 QTest::newRow("qobject, caching + read")
2984 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2987 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2988 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2994 QTest::newRow("script, caching + read")
2995 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2998 << (QStringList() << "scriptTest")
2999 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3005 QTest::newRow("qobject, writing + readonly constraints")
3006 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
3008 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3009 << (QStringList() << "readOnlyProperty" << "writableProperty")
3010 << (QVariantList() << 20 << 50)
3011 << (QStringList() << "firstProperty" << "writableProperty")
3012 << (QVariantList() << 30 << 30)
3013 << (QStringList() << "readOnlyProperty" << "writableProperty")
3014 << (QVariantList() << 20 << 30);
3016 QTest::newRow("script, writing + readonly constraints")
3017 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
3019 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3020 << (QStringList() << "readBack" << "unchanged")
3021 << (QVariantList() << 13 << 42)
3022 << (QStringList() << "firstProperty" << "secondProperty")
3023 << (QVariantList() << 30 << 30)
3024 << (QStringList() << "readBack" << "unchanged")
3025 << (QVariantList() << 30 << 42);
3027 QTest::newRow("qobject module API enum values in JS")
3028 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3031 << (QStringList() << "enumValue" << "enumMethod")
3032 << (QVariantList() << 42 << 30)
3038 QTest::newRow("qobject, invalid major version fail")
3039 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3040 << QString("QDeclarativeComponent: Component is not ready")
3049 QTest::newRow("qobject, invalid minor version fail")
3050 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3051 << QString("QDeclarativeComponent: Component is not ready")
3061 void tst_qdeclarativeecmascript::moduleApi()
3063 QFETCH(QUrl, testfile);
3064 QFETCH(QString, errorMessage);
3065 QFETCH(QStringList, warningMessages);
3066 QFETCH(QStringList, readProperties);
3067 QFETCH(QVariantList, readExpectedValues);
3068 QFETCH(QStringList, writeProperties);
3069 QFETCH(QVariantList, writeValues);
3070 QFETCH(QStringList, readBackProperties);
3071 QFETCH(QVariantList, readBackExpectedValues);
3073 QDeclarativeComponent component(&engine, testfile);
3075 if (!errorMessage.isEmpty())
3076 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3078 if (warningMessages.size())
3079 foreach (const QString &warning, warningMessages)
3080 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3082 QObject *object = component.create();
3083 if (!errorMessage.isEmpty()) {
3084 QVERIFY(object == 0);
3086 QVERIFY(object != 0);
3087 for (int i = 0; i < readProperties.size(); ++i)
3088 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3089 for (int i = 0; i < writeProperties.size(); ++i)
3090 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3091 for (int i = 0; i < readBackProperties.size(); ++i)
3092 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3097 void tst_qdeclarativeecmascript::importScripts_data()
3099 QTest::addColumn<QUrl>("testfile");
3100 QTest::addColumn<QString>("errorMessage");
3101 QTest::addColumn<QStringList>("warningMessages");
3102 QTest::addColumn<QStringList>("propertyNames");
3103 QTest::addColumn<QVariantList>("propertyValues");
3105 QTest::newRow("basic functionality")
3106 << TEST_FILE("jsimport/testImport.qml")
3109 << (QStringList() << QLatin1String("importedScriptStringValue")
3110 << QLatin1String("importedScriptFunctionValue")
3111 << QLatin1String("importedModuleAttachedPropertyValue")
3112 << QLatin1String("importedModuleEnumValue"))
3113 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3118 QTest::newRow("import scoping")
3119 << TEST_FILE("jsimport/testImportScoping.qml")
3122 << (QStringList() << QLatin1String("componentError"))
3123 << (QVariantList() << QVariant(5));
3125 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3126 << TEST_FILE("jsimportfail/failOne.qml")
3128 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3129 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3130 << (QVariantList() << QVariant(QString()));
3132 QTest::newRow("javascript imports in an import should be private to the import scope")
3133 << TEST_FILE("jsimportfail/failTwo.qml")
3135 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3136 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3137 << (QVariantList() << QVariant(QString()));
3139 QTest::newRow("module imports in an import should be private to the import scope")
3140 << TEST_FILE("jsimportfail/failThree.qml")
3142 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3143 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3144 << (QVariantList() << QVariant(false));
3146 QTest::newRow("typenames in an import should be private to the import scope")
3147 << TEST_FILE("jsimportfail/failFour.qml")
3149 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3150 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3151 << (QVariantList() << QVariant(0));
3153 QTest::newRow("import with imports has it's own activation scope")
3154 << TEST_FILE("jsimportfail/failFive.qml")
3156 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3157 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3158 << (QStringList() << QLatin1String("componentError"))
3159 << (QVariantList() << QVariant(0));
3161 QTest::newRow("import pragma library script")
3162 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3165 << (QStringList() << QLatin1String("testValue"))
3166 << (QVariantList() << QVariant(31));
3168 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3169 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3172 << (QStringList() << QLatin1String("testValue"))
3173 << (QVariantList() << QVariant(0));
3175 QTest::newRow("import pragma library script which has an import")
3176 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3179 << (QStringList() << QLatin1String("testValue"))
3180 << (QVariantList() << QVariant(55));
3182 QTest::newRow("import pragma library script which has a pragma library import")
3183 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3186 << (QStringList() << QLatin1String("testValue"))
3187 << (QVariantList() << QVariant(18));
3190 void tst_qdeclarativeecmascript::importScripts()
3192 QFETCH(QUrl, testfile);
3193 QFETCH(QString, errorMessage);
3194 QFETCH(QStringList, warningMessages);
3195 QFETCH(QStringList, propertyNames);
3196 QFETCH(QVariantList, propertyValues);
3198 QDeclarativeComponent component(&engine, testfile);
3200 if (!errorMessage.isEmpty())
3201 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3203 if (warningMessages.size())
3204 foreach (const QString &warning, warningMessages)
3205 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3207 QObject *object = component.create();
3208 if (!errorMessage.isEmpty()) {
3209 QVERIFY(object == 0);
3211 QVERIFY(object != 0);
3212 for (int i = 0; i < propertyNames.size(); ++i)
3213 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3218 void tst_qdeclarativeecmascript::scarceResources_other()
3220 /* These tests require knowledge of state, since we test values after
3221 performing signal or function invocation. */
3223 QPixmap origPixmap(100, 100);
3224 origPixmap.fill(Qt::blue);
3225 QString srp_name, expectedWarning;
3226 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3227 ScarceResourceObject *eo = 0;
3229 QObject *object = 0;
3231 /* property var semantics */
3233 // test that scarce resources are handled properly in signal invocation
3234 QDeclarativeComponent varComponentTen(&engine, TEST_FILE("scarceResourceSignal.var.qml"));
3235 object = varComponentTen.create();
3236 srsc = object->findChild<QObject*>("srsc");
3238 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3239 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3240 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3241 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3242 QMetaObject::invokeMethod(srsc, "testSignal");
3243 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3244 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3245 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3246 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3247 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3248 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3249 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3250 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3251 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3252 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3255 // test that scarce resources are handled properly from js functions in qml files
3256 QDeclarativeComponent varComponentEleven(&engine, TEST_FILE("scarceResourceFunction.var.qml"));
3257 object = varComponentEleven.create();
3258 QVERIFY(object != 0);
3259 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3260 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3261 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3262 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3263 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3264 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3265 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3266 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3267 QMetaObject::invokeMethod(object, "releaseScarceResource");
3268 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3269 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3270 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3271 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3274 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3275 QDeclarativeComponent varComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
3276 object = varComponentTwelve.create();
3277 QVERIFY(object != 0);
3278 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3279 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3280 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3281 srp_name = object->property("srp_name").toString();
3282 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3283 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3284 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3285 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
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 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3291 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3292 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3293 QDeclarativeComponent varComponentThirteen(&engine, TEST_FILE("scarceResourceObjectGc.var.qml"));
3294 object = varComponentThirteen.create();
3295 QVERIFY(object != 0);
3296 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3297 QMetaObject::invokeMethod(object, "assignVarProperty");
3298 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3299 QMetaObject::invokeMethod(object, "deassignVarProperty");
3300 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3303 /* property variant semantics */
3305 // test that scarce resources are handled properly in signal invocation
3306 QDeclarativeComponent variantComponentTen(&engine, TEST_FILE("scarceResourceSignal.variant.qml"));
3307 object = variantComponentTen.create();
3308 QVERIFY(object != 0);
3309 srsc = object->findChild<QObject*>("srsc");
3311 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3312 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3313 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3314 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3315 QMetaObject::invokeMethod(srsc, "testSignal");
3316 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3317 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3318 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3319 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3320 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3321 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3322 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3323 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3324 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3325 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3328 // test that scarce resources are handled properly from js functions in qml files
3329 QDeclarativeComponent variantComponentEleven(&engine, TEST_FILE("scarceResourceFunction.variant.qml"));
3330 object = variantComponentEleven.create();
3331 QVERIFY(object != 0);
3332 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3333 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3334 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3335 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3336 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3337 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3338 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3339 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3340 QMetaObject::invokeMethod(object, "releaseScarceResource");
3341 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3342 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3343 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3344 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3347 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3348 QDeclarativeComponent variantComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.variant.qml"));
3349 object = variantComponentTwelve.create();
3350 QVERIFY(object != 0);
3351 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3352 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3353 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3354 srp_name = object->property("srp_name").toString();
3355 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3356 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3357 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3358 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
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 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3365 void tst_qdeclarativeecmascript::scarceResources_data()
3367 QTest::addColumn<QUrl>("qmlFile");
3368 QTest::addColumn<bool>("readDetachStatus");
3369 QTest::addColumn<bool>("expectedDetachStatus");
3370 QTest::addColumn<QStringList>("propertyNames");
3371 QTest::addColumn<QVariantList>("expectedValidity");
3372 QTest::addColumn<QVariantList>("expectedValues");
3373 QTest::addColumn<QStringList>("expectedErrors");
3375 QPixmap origPixmap(100, 100);
3376 origPixmap.fill(Qt::blue);
3378 /* property var semantics */
3380 // in the following three cases, the instance created from the component
3381 // has a property which is a copy of the scarce resource; hence, the
3382 // resource should NOT be detached prior to deletion of the object instance,
3383 // unless the resource is destroyed explicitly.
3384 QTest::newRow("var: import scarce resource copy directly")
3385 << TEST_FILE("scarceResourceCopy.var.qml")
3387 << false // won't be detached, because assigned to property and not explicitly released
3388 << (QStringList() << QLatin1String("scarceResourceCopy"))
3389 << (QList<QVariant>() << true)
3390 << (QList<QVariant>() << origPixmap)
3393 QTest::newRow("var: import scarce resource copy from JS")
3394 << TEST_FILE("scarceResourceCopyFromJs.var.qml")
3396 << false // won't be detached, because assigned to property and not explicitly released
3397 << (QStringList() << QLatin1String("scarceResourceCopy"))
3398 << (QList<QVariant>() << true)
3399 << (QList<QVariant>() << origPixmap)
3402 QTest::newRow("var: import released scarce resource copy from JS")
3403 << TEST_FILE("scarceResourceDestroyedCopy.var.qml")
3405 << true // explicitly released, so it will be detached
3406 << (QStringList() << QLatin1String("scarceResourceCopy"))
3407 << (QList<QVariant>() << false)
3408 << (QList<QVariant>() << QVariant())
3411 // in the following three cases, no other copy should exist in memory,
3412 // and so it should be detached (unless explicitly preserved).
3413 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3414 << TEST_FILE("scarceResourceTest.var.qml")
3416 << true // auto released, so it will be detached
3417 << (QStringList() << QLatin1String("scarceResourceTest"))
3418 << (QList<QVariant>() << true)
3419 << (QList<QVariant>() << QVariant(100))
3421 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3422 << TEST_FILE("scarceResourceTestPreserve.var.qml")
3424 << false // won't be detached because we explicitly preserve it
3425 << (QStringList() << QLatin1String("scarceResourceTest"))
3426 << (QList<QVariant>() << true)
3427 << (QList<QVariant>() << QVariant(100))
3429 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3430 << TEST_FILE("scarceResourceTestMultiple.var.qml")
3432 << true // will be detached because all resources were released manually or automatically.
3433 << (QStringList() << QLatin1String("scarceResourceTest"))
3434 << (QList<QVariant>() << true)
3435 << (QList<QVariant>() << QVariant(100))
3438 // In the following three cases, test that scarce resources are handled
3439 // correctly for imports.
3440 QTest::newRow("var: import with no binding")
3441 << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
3442 << false // cannot check detach status.
3445 << QList<QVariant>()
3446 << QList<QVariant>()
3448 QTest::newRow("var: import with binding without explicit preserve")
3449 << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
3452 << (QStringList() << QLatin1String("scarceResourceCopy"))
3453 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3454 << (QList<QVariant>() << QVariant())
3456 QTest::newRow("var: import with explicit release after binding evaluation")
3457 << TEST_FILE("scarceResourceCopyImport.var.qml")
3460 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3461 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3462 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3464 QTest::newRow("var: import with different js objects")
3465 << TEST_FILE("scarceResourceCopyImportDifferent.var.qml")
3468 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3469 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3470 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3472 QTest::newRow("var: import with different js objects and explicit release")
3473 << TEST_FILE("scarceResourceMultipleDifferentNoBinding.var.qml")
3476 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3477 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3478 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3480 QTest::newRow("var: import with same js objects and explicit release")
3481 << TEST_FILE("scarceResourceMultipleSameNoBinding.var.qml")
3484 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3485 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3486 << (QList<QVariant>() << QVariant() << QVariant())
3488 QTest::newRow("var: binding with same js objects and explicit release")
3489 << TEST_FILE("scarceResourceMultipleSameWithBinding.var.qml")
3492 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3493 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3494 << (QList<QVariant>() << QVariant() << QVariant())
3498 /* property variant semantics */
3500 // in the following three cases, the instance created from the component
3501 // has a property which is a copy of the scarce resource; hence, the
3502 // resource should NOT be detached prior to deletion of the object instance,
3503 // unless the resource is destroyed explicitly.
3504 QTest::newRow("variant: import scarce resource copy directly")
3505 << TEST_FILE("scarceResourceCopy.variant.qml")
3507 << false // won't be detached, because assigned to property and not explicitly released
3508 << (QStringList() << QLatin1String("scarceResourceCopy"))
3509 << (QList<QVariant>() << true)
3510 << (QList<QVariant>() << origPixmap)
3513 QTest::newRow("variant: import scarce resource copy from JS")
3514 << TEST_FILE("scarceResourceCopyFromJs.variant.qml")
3516 << false // won't be detached, because assigned to property and not explicitly released
3517 << (QStringList() << QLatin1String("scarceResourceCopy"))
3518 << (QList<QVariant>() << true)
3519 << (QList<QVariant>() << origPixmap)
3522 QTest::newRow("variant: import released scarce resource copy from JS")
3523 << TEST_FILE("scarceResourceDestroyedCopy.variant.qml")
3525 << true // explicitly released, so it will be detached
3526 << (QStringList() << QLatin1String("scarceResourceCopy"))
3527 << (QList<QVariant>() << false)
3528 << (QList<QVariant>() << QVariant())
3531 // in the following three cases, no other copy should exist in memory,
3532 // and so it should be detached (unless explicitly preserved).
3533 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3534 << TEST_FILE("scarceResourceTest.variant.qml")
3536 << true // auto released, so it will be detached
3537 << (QStringList() << QLatin1String("scarceResourceTest"))
3538 << (QList<QVariant>() << true)
3539 << (QList<QVariant>() << QVariant(100))
3541 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3542 << TEST_FILE("scarceResourceTestPreserve.variant.qml")
3544 << false // won't be detached because we explicitly preserve it
3545 << (QStringList() << QLatin1String("scarceResourceTest"))
3546 << (QList<QVariant>() << true)
3547 << (QList<QVariant>() << QVariant(100))
3549 QTest::newRow("variant: import multiple scarce resources")
3550 << TEST_FILE("scarceResourceTestMultiple.variant.qml")
3552 << true // will be detached because all resources were released manually or automatically.
3553 << (QStringList() << QLatin1String("scarceResourceTest"))
3554 << (QList<QVariant>() << true)
3555 << (QList<QVariant>() << QVariant(100))
3558 // In the following three cases, test that scarce resources are handled
3559 // correctly for imports.
3560 QTest::newRow("variant: import with no binding")
3561 << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
3562 << false // cannot check detach status.
3565 << QList<QVariant>()
3566 << QList<QVariant>()
3568 QTest::newRow("variant: import with binding without explicit preserve")
3569 << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
3572 << (QStringList() << QLatin1String("scarceResourceCopy"))
3573 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3574 << (QList<QVariant>() << QVariant())
3576 QTest::newRow("variant: import with explicit release after binding evaluation")
3577 << TEST_FILE("scarceResourceCopyImport.variant.qml")
3580 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3581 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3582 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3586 void tst_qdeclarativeecmascript::scarceResources()
3588 QFETCH(QUrl, qmlFile);
3589 QFETCH(bool, readDetachStatus);
3590 QFETCH(bool, expectedDetachStatus);
3591 QFETCH(QStringList, propertyNames);
3592 QFETCH(QVariantList, expectedValidity);
3593 QFETCH(QVariantList, expectedValues);
3594 QFETCH(QStringList, expectedErrors);
3596 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3597 ScarceResourceObject *eo = 0;
3598 QObject *object = 0;
3600 QDeclarativeComponent c(&engine, qmlFile);
3601 object = c.create();
3602 QVERIFY(object != 0);
3603 for (int i = 0; i < propertyNames.size(); ++i) {
3604 QString prop = propertyNames.at(i);
3605 bool validity = expectedValidity.at(i).toBool();
3606 QVariant value = expectedValues.at(i);
3608 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3609 if (value.type() == QVariant::Int) {
3610 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3611 } else if (value.type() == QVariant::Pixmap) {
3612 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3616 if (readDetachStatus) {
3617 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3618 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3621 QVERIFY(ep->scarceResources.isEmpty());
3625 void tst_qdeclarativeecmascript::propertyChangeSlots()
3627 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3628 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3629 QObject *object = component.create();
3630 QVERIFY(object != 0);
3633 // ensure that invalid property names fail properly.
3634 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3635 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3636 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3637 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3638 object = e1.create();
3639 QVERIFY(object == 0);
3642 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3643 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3644 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3645 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3646 object = e2.create();
3647 QVERIFY(object == 0);
3650 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3651 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3652 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3653 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3654 object = e3.create();
3655 QVERIFY(object == 0);
3658 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3659 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3660 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3661 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3662 object = e4.create();
3663 QVERIFY(object == 0);
3667 void tst_qdeclarativeecmascript::propertyVar_data()
3669 QTest::addColumn<QUrl>("qmlFile");
3672 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3673 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3674 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3675 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3676 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3677 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3678 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3679 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3680 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3683 void tst_qdeclarativeecmascript::propertyVar()
3685 QFETCH(QUrl, qmlFile);
3687 QDeclarativeComponent component(&engine, qmlFile);
3688 QObject *object = component.create();
3689 QVERIFY(object != 0);
3691 QCOMPARE(object->property("test").toBool(), true);
3696 // Tests that we can write QVariant values to var properties from C++
3697 void tst_qdeclarativeecmascript::propertyVarCpp()
3699 QObject *object = 0;
3701 // ensure that writing to and reading from a var property from cpp works as required.
3702 // Literal values stored in var properties can be read and written as QVariants
3703 // of a specific type, whereas object values are read as QVariantMaps.
3704 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3705 object = component.create();
3706 QVERIFY(object != 0);
3707 // assign int to property var that currently has int assigned
3708 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3709 QCOMPARE(object->property("varBound"), QVariant(15));
3710 QCOMPARE(object->property("intBound"), QVariant(15));
3711 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3712 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3713 // assign string to property var that current has bool assigned
3714 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3715 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3716 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3717 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3718 // now enforce behaviour when accessing JavaScript objects from cpp.
3719 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3723 static void gc(QDeclarativeEngine &engine)
3725 engine.collectGarbage();
3726 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3729 void tst_qdeclarativeecmascript::propertyVarOwnership()
3731 // Referenced JS objects are not collected
3733 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3734 QObject *object = component.create();
3735 QVERIFY(object != 0);
3736 QCOMPARE(object->property("test").toBool(), false);
3737 QMetaObject::invokeMethod(object, "runTest");
3738 QCOMPARE(object->property("test").toBool(), true);
3741 // Referenced JS objects are not collected
3743 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3744 QObject *object = component.create();
3745 QVERIFY(object != 0);
3746 QCOMPARE(object->property("test").toBool(), false);
3747 QMetaObject::invokeMethod(object, "runTest");
3748 QCOMPARE(object->property("test").toBool(), true);
3751 // Qt objects are not collected until they've been dereferenced
3753 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3754 QObject *object = component.create();
3755 QVERIFY(object != 0);
3757 QCOMPARE(object->property("test2").toBool(), false);
3758 QCOMPARE(object->property("test2").toBool(), false);
3760 QMetaObject::invokeMethod(object, "runTest");
3761 QCOMPARE(object->property("test1").toBool(), true);
3763 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3764 QVERIFY(!referencedObject.isNull());
3766 QVERIFY(!referencedObject.isNull());
3768 QMetaObject::invokeMethod(object, "runTest2");
3769 QCOMPARE(object->property("test2").toBool(), true);
3771 QVERIFY(referencedObject.isNull());
3775 // Self reference does not prevent Qt object collection
3777 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3778 QObject *object = component.create();
3779 QVERIFY(object != 0);
3781 QCOMPARE(object->property("test").toBool(), true);
3783 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3784 QVERIFY(!referencedObject.isNull());
3786 QVERIFY(!referencedObject.isNull());
3788 QMetaObject::invokeMethod(object, "runTest");
3790 QVERIFY(referencedObject.isNull());
3796 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3798 // The childObject has a reference to a different QObject. We want to ensure
3799 // that the different item will not be cleaned up until required. IE, the childObject
3800 // has implicit ownership of the constructed QObject.
3801 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3802 QObject *object = component.create();
3803 QVERIFY(object != 0);
3804 QMetaObject::invokeMethod(object, "assignCircular");
3805 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3806 QObject *rootObject = object->property("vp").value<QObject*>();
3807 QVERIFY(rootObject != 0);
3808 QObject *childObject = rootObject->findChild<QObject*>("text");
3809 QVERIFY(childObject != 0);
3810 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3811 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3812 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3813 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3814 QVERIFY(!qobjectGuard.isNull());
3815 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3816 QVERIFY(!qobjectGuard.isNull());
3817 QMetaObject::invokeMethod(object, "deassignCircular");
3818 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3819 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3823 void tst_qdeclarativeecmascript::propertyVarReparent()
3825 // ensure that nothing breaks if we re-parent objects
3826 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3827 QObject *object = component.create();
3828 QVERIFY(object != 0);
3829 QMetaObject::invokeMethod(object, "assignVarProp");
3830 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3831 QObject *rect = object->property("vp").value<QObject*>();
3832 QObject *text = rect->findChild<QObject*>("textOne");
3833 QObject *text2 = rect->findChild<QObject*>("textTwo");
3834 QWeakPointer<QObject> rectGuard(rect);
3835 QWeakPointer<QObject> textGuard(text);
3836 QWeakPointer<QObject> text2Guard(text2);
3837 QVERIFY(!rectGuard.isNull());
3838 QVERIFY(!textGuard.isNull());
3839 QVERIFY(!text2Guard.isNull());
3840 QCOMPARE(text->property("textCanary").toInt(), 11);
3841 QCOMPARE(text2->property("textCanary").toInt(), 12);
3842 // now construct an image which we will reparent.
3843 QMetaObject::invokeMethod(text2, "constructQObject");
3844 QObject *image = text2->property("vp").value<QObject*>();
3845 QWeakPointer<QObject> imageGuard(image);
3846 QVERIFY(!imageGuard.isNull());
3847 QCOMPARE(image->property("imageCanary").toInt(), 13);
3848 // now reparent the "Image" object (currently, it has JS ownership)
3849 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3850 QMetaObject::invokeMethod(text2, "deassignVp");
3851 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3852 QCOMPARE(text->property("textCanary").toInt(), 11);
3853 QCOMPARE(text2->property("textCanary").toInt(), 22);
3854 QVERIFY(!imageGuard.isNull()); // should still be alive.
3855 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3856 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3857 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3858 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3862 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3864 // sometimes reparenting can cause problems
3865 // (eg, if the ctxt is collected, varproperties are no longer available)
3866 // this test ensures that no crash occurs in that situation.
3867 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3868 QObject *object = component.create();
3869 QVERIFY(object != 0);
3870 QMetaObject::invokeMethod(object, "assignVarProp");
3871 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3872 QObject *rect = object->property("vp").value<QObject*>();
3873 QObject *text = rect->findChild<QObject*>("textOne");
3874 QObject *text2 = rect->findChild<QObject*>("textTwo");
3875 QWeakPointer<QObject> rectGuard(rect);
3876 QWeakPointer<QObject> textGuard(text);
3877 QWeakPointer<QObject> text2Guard(text2);
3878 QVERIFY(!rectGuard.isNull());
3879 QVERIFY(!textGuard.isNull());
3880 QVERIFY(!text2Guard.isNull());
3881 QCOMPARE(text->property("textCanary").toInt(), 11);
3882 QCOMPARE(text2->property("textCanary").toInt(), 12);
3883 // now construct an image which we will reparent.
3884 QMetaObject::invokeMethod(text2, "constructQObject");
3885 QObject *image = text2->property("vp").value<QObject*>();
3886 QWeakPointer<QObject> imageGuard(image);
3887 QVERIFY(!imageGuard.isNull());
3888 QCOMPARE(image->property("imageCanary").toInt(), 13);
3889 // now reparent the "Image" object (currently, it has JS ownership)
3890 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3891 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3892 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3893 QVERIFY(!imageGuard.isNull()); // should still be alive.
3894 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3896 QVERIFY(imageGuard.isNull()); // should now be dead.
3899 void tst_qdeclarativeecmascript::propertyVarCircular()
3901 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3902 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3903 QObject *object = component.create();
3904 QVERIFY(object != 0);
3905 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3906 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3907 QCOMPARE(object->property("canaryInt"), QVariant(5));
3908 QVariant canaryResourceVariant = object->property("canaryResource");
3909 QVERIFY(canaryResourceVariant.isValid());
3910 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3911 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3912 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3913 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3914 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3915 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3916 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3917 QCOMPARE(object->property("canaryInt"), QVariant(2));
3918 QCOMPARE(object->property("canaryResource"), QVariant(1));
3919 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3923 void tst_qdeclarativeecmascript::propertyVarCircular2()
3925 // track deletion of JS-owned parent item with Cpp-owned child
3926 // where the child has a var property referencing its parent.
3927 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3928 QObject *object = component.create();
3929 QVERIFY(object != 0);
3930 QMetaObject::invokeMethod(object, "assignCircular");
3931 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3932 QObject *rootObject = object->property("vp").value<QObject*>();
3933 QVERIFY(rootObject != 0);
3934 QObject *childObject = rootObject->findChild<QObject*>("text");
3935 QVERIFY(childObject != 0);
3936 QWeakPointer<QObject> rootObjectTracker(rootObject);
3937 QVERIFY(!rootObjectTracker.isNull());
3938 QWeakPointer<QObject> childObjectTracker(childObject);
3939 QVERIFY(!childObjectTracker.isNull());
3941 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3942 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3943 QMetaObject::invokeMethod(object, "deassignCircular");
3944 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3945 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3946 QVERIFY(childObjectTracker.isNull()); // should have been collected
3950 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3952 *(int*)(parameter) += 1;
3953 qPersistentDispose(object);
3956 void tst_qdeclarativeecmascript::propertyVarInheritance()
3958 int propertyVarWeakRefCallbackCount = 0;
3960 // enforce behaviour regarding element inheritance - ensure handle disposal.
3961 // The particular component under test here has a chain of references.
3962 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3963 QObject *object = component.create();
3964 QVERIFY(object != 0);
3965 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3966 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3967 // we want to be able to track when the varProperties array of the last metaobject is disposed
3968 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3969 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*>();
3970 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3971 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3972 v8::Persistent<v8::Value> icoCanaryHandle;
3973 v8::Persistent<v8::Value> ccoCanaryHandle;
3976 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3977 // public function which can return us a handle to something in the varProperties array.
3978 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3979 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3980 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3981 // as the varproperties array of each vmemo still references the resource.
3982 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3983 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3985 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3987 // now we deassign the var prop, which should trigger collection of item subtrees.
3988 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3989 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3990 // ensure that there are only weak handles to the underlying varProperties array remaining.
3992 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3994 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3995 // to what remains are weak, all varProperties arrays must have been collected.
3998 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4000 int propertyVarWeakRefCallbackCount = 0;
4002 // The particular component under test here does NOT have a chain of references; the
4003 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4004 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
4005 QObject *object = component.create();
4006 QVERIFY(object != 0);
4007 QMetaObject::invokeMethod(object, "assignCircular");
4008 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4009 QObject *rootObject = object->property("vp").value<QObject*>();
4010 QVERIFY(rootObject != 0);
4011 QObject *childObject = rootObject->findChild<QObject*>("text");
4012 QVERIFY(childObject != 0);
4013 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4014 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4015 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4018 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4019 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
4020 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4022 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4023 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4025 QMetaObject::invokeMethod(object, "deassignCircular");
4026 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4027 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4031 // Ensure that QObject type conversion works on binding assignment
4032 void tst_qdeclarativeecmascript::elementAssign()
4034 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
4036 QObject *object = component.create();
4037 QVERIFY(object != 0);
4039 QCOMPARE(object->property("test").toBool(), true);
4045 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4047 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
4049 QObject *object = component.create();
4050 QVERIFY(object != 0);
4052 QCOMPARE(object->property("test").toBool(), true);
4058 void tst_qdeclarativeecmascript::objectConversion()
4060 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
4062 QObject *object = component.create();
4063 QVERIFY(object != 0);
4065 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4066 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4073 void tst_qdeclarativeecmascript::booleanConversion()
4075 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
4077 QObject *object = component.create();
4078 QVERIFY(object != 0);
4080 QCOMPARE(object->property("test_true1").toBool(), true);
4081 QCOMPARE(object->property("test_true2").toBool(), true);
4082 QCOMPARE(object->property("test_true3").toBool(), true);
4083 QCOMPARE(object->property("test_true4").toBool(), true);
4084 QCOMPARE(object->property("test_true5").toBool(), true);
4086 QCOMPARE(object->property("test_false1").toBool(), false);
4087 QCOMPARE(object->property("test_false2").toBool(), false);
4088 QCOMPARE(object->property("test_false3").toBool(), false);
4093 void tst_qdeclarativeecmascript::handleReferenceManagement()
4098 // Linear QObject reference
4099 QDeclarativeEngine hrmEngine;
4100 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
4101 QObject *object = component.create();
4102 QVERIFY(object != 0);
4103 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4104 cro->setDtorCount(&dtorCount);
4105 QMetaObject::invokeMethod(object, "createReference");
4107 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4109 hrmEngine.collectGarbage();
4110 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4111 QCOMPARE(dtorCount, 3);
4116 // Circular QObject reference
4117 QDeclarativeEngine hrmEngine;
4118 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
4119 QObject *object = component.create();
4120 QVERIFY(object != 0);
4121 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4122 cro->setDtorCount(&dtorCount);
4123 QMetaObject::invokeMethod(object, "circularReference");
4125 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4127 hrmEngine.collectGarbage();
4128 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4129 QCOMPARE(dtorCount, 3);
4134 // Linear handle reference
4135 QDeclarativeEngine hrmEngine;
4136 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4137 QObject *object = component.create();
4138 QVERIFY(object != 0);
4139 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4141 crh->setDtorCount(&dtorCount);
4142 QMetaObject::invokeMethod(object, "createReference");
4143 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4144 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4145 QVERIFY(first != 0);
4146 QVERIFY(second != 0);
4147 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4148 // now we have to reparent second and make second owned by JS.
4149 second->setParent(0);
4150 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4152 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4154 hrmEngine.collectGarbage();
4155 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4156 QCOMPARE(dtorCount, 3);
4161 // Circular handle reference
4162 QDeclarativeEngine hrmEngine;
4163 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
4164 QObject *object = component.create();
4165 QVERIFY(object != 0);
4166 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4168 crh->setDtorCount(&dtorCount);
4169 QMetaObject::invokeMethod(object, "circularReference");
4170 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4171 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4172 QVERIFY(first != 0);
4173 QVERIFY(second != 0);
4174 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4175 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4176 // now we have to reparent and change ownership.
4177 first->setParent(0);
4178 second->setParent(0);
4179 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4180 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4182 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4184 hrmEngine.collectGarbage();
4185 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4186 QCOMPARE(dtorCount, 3);
4191 // multiple engine interaction - linear reference
4192 QDeclarativeEngine hrmEngine1;
4193 QDeclarativeEngine hrmEngine2;
4194 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4195 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4196 QObject *object1 = component1.create();
4197 QObject *object2 = component2.create();
4198 QVERIFY(object1 != 0);
4199 QVERIFY(object2 != 0);
4200 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4201 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4204 crh1->setDtorCount(&dtorCount);
4205 crh2->setDtorCount(&dtorCount);
4206 QMetaObject::invokeMethod(object1, "createReference");
4207 QMetaObject::invokeMethod(object2, "createReference");
4208 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4209 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4210 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4211 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4212 QVERIFY(first1 != 0);
4213 QVERIFY(second1 != 0);
4214 QVERIFY(first2 != 0);
4215 QVERIFY(second2 != 0);
4216 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4217 // now we have to reparent second2 and make second2 owned by JS.
4218 second2->setParent(0);
4219 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4221 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4222 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4225 hrmEngine1.collectGarbage();
4226 hrmEngine2.collectGarbage();
4227 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4228 QCOMPARE(dtorCount, 6);
4233 // multiple engine interaction - circular reference
4234 QDeclarativeEngine hrmEngine1;
4235 QDeclarativeEngine hrmEngine2;
4236 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4237 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4238 QObject *object1 = component1.create();
4239 QObject *object2 = component2.create();
4240 QVERIFY(object1 != 0);
4241 QVERIFY(object2 != 0);
4242 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4243 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4246 crh1->setDtorCount(&dtorCount);
4247 crh2->setDtorCount(&dtorCount);
4248 QMetaObject::invokeMethod(object1, "createReference");
4249 QMetaObject::invokeMethod(object2, "createReference");
4250 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4251 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4252 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4253 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4254 QVERIFY(first1 != 0);
4255 QVERIFY(second1 != 0);
4256 QVERIFY(first2 != 0);
4257 QVERIFY(second2 != 0);
4258 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4259 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4260 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4261 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4262 // now we have to reparent and change ownership to JS.
4263 first1->setParent(0);
4264 second1->setParent(0);
4265 first2->setParent(0);
4266 second2->setParent(0);
4267 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4268 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4269 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4270 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4272 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4273 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4276 hrmEngine1.collectGarbage();
4277 hrmEngine2.collectGarbage();
4278 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4279 QCOMPARE(dtorCount, 6);
4284 // multiple engine interaction - linear reference with engine deletion
4285 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4286 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4287 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4288 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4289 QObject *object1 = component1.create();
4290 QObject *object2 = component2.create();
4291 QVERIFY(object1 != 0);
4292 QVERIFY(object2 != 0);
4293 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4294 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4297 crh1->setDtorCount(&dtorCount);
4298 crh2->setDtorCount(&dtorCount);
4299 QMetaObject::invokeMethod(object1, "createReference");
4300 QMetaObject::invokeMethod(object2, "createReference");
4301 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4302 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4303 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4304 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4305 QVERIFY(first1 != 0);
4306 QVERIFY(second1 != 0);
4307 QVERIFY(first2 != 0);
4308 QVERIFY(second2 != 0);
4309 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4310 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4311 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4312 // now we have to reparent and change ownership to JS.
4313 first1->setParent(crh1);
4314 second1->setParent(0);
4315 first2->setParent(0);
4316 second2->setParent(0);
4317 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4318 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4319 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4321 QCOMPARE(dtorCount, 0);
4324 QCOMPARE(dtorCount, 0);
4327 hrmEngine1->collectGarbage();
4328 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4329 QCOMPARE(dtorCount, 6);
4334 void tst_qdeclarativeecmascript::stringArg()
4336 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4337 QObject *object = component.create();
4338 QVERIFY(object != 0);
4339 QMetaObject::invokeMethod(object, "success");
4340 QVERIFY(object->property("returnValue").toBool());
4342 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4343 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4344 QMetaObject::invokeMethod(object, "failure");
4345 QVERIFY(object->property("returnValue").toBool());
4350 void tst_qdeclarativeecmascript::readonlyDeclaration()
4352 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4354 QObject *object = component.create();
4355 QVERIFY(object != 0);
4357 QCOMPARE(object->property("test").toBool(), true);
4362 Q_DECLARE_METATYPE(QList<int>)
4363 Q_DECLARE_METATYPE(QList<qreal>)
4364 Q_DECLARE_METATYPE(QList<bool>)
4365 Q_DECLARE_METATYPE(QList<QString>)
4366 Q_DECLARE_METATYPE(QList<QUrl>)
4367 void tst_qdeclarativeecmascript::sequenceConversionRead()
4370 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4371 QDeclarativeComponent component(&engine, qmlFile);
4372 QObject *object = component.create();
4373 QVERIFY(object != 0);
4374 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4377 QMetaObject::invokeMethod(object, "readSequences");
4378 QList<int> intList; intList << 1 << 2 << 3 << 4;
4379 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4380 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4381 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4382 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4383 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4384 QList<bool> boolList; boolList << true << false << true << false;
4385 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4386 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4387 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4388 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4389 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4390 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4391 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4392 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4393 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4394 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4395 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4397 QMetaObject::invokeMethod(object, "readSequenceElements");
4398 QCOMPARE(object->property("intVal").toInt(), 2);
4399 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4400 QCOMPARE(object->property("boolVal").toBool(), false);
4401 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4402 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4403 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4405 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4406 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4408 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4409 QDeclarativeProperty seqProp(seq, "intListProperty");
4410 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4411 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4412 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4414 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4415 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4421 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4422 QDeclarativeComponent component(&engine, qmlFile);
4423 QObject *object = component.create();
4424 QVERIFY(object != 0);
4425 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4428 // we haven't registered QList<QPoint> as a sequence type.
4429 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4430 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4431 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4432 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4434 QMetaObject::invokeMethod(object, "performTest");
4436 // QList<QPoint> has not been registered as a sequence type.
4437 QCOMPARE(object->property("pointListLength").toInt(), 0);
4438 QVERIFY(!object->property("pointList").isValid());
4439 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4440 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4441 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4447 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4450 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4451 QDeclarativeComponent component(&engine, qmlFile);
4452 QObject *object = component.create();
4453 QVERIFY(object != 0);
4454 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4457 QMetaObject::invokeMethod(object, "writeSequences");
4458 QCOMPARE(object->property("success").toBool(), true);
4460 QMetaObject::invokeMethod(object, "writeSequenceElements");
4461 QCOMPARE(object->property("success").toBool(), true);
4463 QMetaObject::invokeMethod(object, "writeOtherElements");
4464 QCOMPARE(object->property("success").toBool(), true);
4466 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4467 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4473 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4474 QDeclarativeComponent component(&engine, qmlFile);
4475 QObject *object = component.create();
4476 QVERIFY(object != 0);
4477 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4480 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4481 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4482 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4484 QMetaObject::invokeMethod(object, "performTest");
4486 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4487 QCOMPARE(seq->pointListProperty(), pointList);
4493 void tst_qdeclarativeecmascript::sequenceConversionArray()
4495 // ensure that in JS the returned sequences act just like normal JS Arrays.
4496 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4497 QDeclarativeComponent component(&engine, qmlFile);
4498 QObject *object = component.create();
4499 QVERIFY(object != 0);
4500 QMetaObject::invokeMethod(object, "indexedAccess");
4501 QVERIFY(object->property("success").toBool());
4502 QMetaObject::invokeMethod(object, "arrayOperations");
4503 QVERIFY(object->property("success").toBool());
4504 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4505 QVERIFY(object->property("success").toBool());
4506 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4507 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4511 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4513 // ensure that sequence conversion operations work correctly in a worker thread
4514 // and that serialisation between the main and worker thread succeeds.
4515 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4516 QDeclarativeComponent component(&engine, qmlFile);
4517 QObject *object = component.create();
4518 QVERIFY(object != 0);
4520 QMetaObject::invokeMethod(object, "testIntSequence");
4521 QTRY_VERIFY(object->property("finished").toBool());
4522 QVERIFY(object->property("success").toBool());
4524 QMetaObject::invokeMethod(object, "testQrealSequence");
4525 QTRY_VERIFY(object->property("finished").toBool());
4526 QVERIFY(object->property("success").toBool());
4528 QMetaObject::invokeMethod(object, "testBoolSequence");
4529 QTRY_VERIFY(object->property("finished").toBool());
4530 QVERIFY(object->property("success").toBool());
4532 QMetaObject::invokeMethod(object, "testStringSequence");
4533 QTRY_VERIFY(object->property("finished").toBool());
4534 QVERIFY(object->property("success").toBool());
4536 QMetaObject::invokeMethod(object, "testQStringSequence");
4537 QTRY_VERIFY(object->property("finished").toBool());
4538 QVERIFY(object->property("success").toBool());
4540 QMetaObject::invokeMethod(object, "testUrlSequence");
4541 QTRY_VERIFY(object->property("finished").toBool());
4542 QVERIFY(object->property("success").toBool());
4544 QMetaObject::invokeMethod(object, "testVariantSequence");
4545 QTRY_VERIFY(object->property("finished").toBool());
4546 QVERIFY(object->property("success").toBool());
4551 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4554 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4555 QDeclarativeComponent component(&engine, qmlFile);
4556 QObject *object = component.create();
4557 QVERIFY(object != 0);
4558 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4559 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4560 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4561 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4562 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4567 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4568 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4569 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4570 QDeclarativeComponent component(&engine, qmlFile);
4571 QObject *object = component.create();
4572 QVERIFY(object != 0);
4577 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4579 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4580 QDeclarativeComponent component(&engine, qmlFile);
4581 QObject *object = component.create();
4582 QVERIFY(object != 0);
4583 QMetaObject::invokeMethod(object, "testCopySequences");
4584 QCOMPARE(object->property("success").toBool(), true);
4585 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4586 QCOMPARE(object->property("success").toBool(), true);
4587 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4588 QCOMPARE(object->property("success").toBool(), true);
4592 void tst_qdeclarativeecmascript::assignSequenceTypes()
4594 // test binding array to sequence type property
4596 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.1.qml"));
4597 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4598 QVERIFY(object != 0);
4599 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4600 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4601 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4602 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4603 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4604 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4608 // test binding literal to sequence type property
4610 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.2.qml"));
4611 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4612 QVERIFY(object != 0);
4613 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4614 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4615 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4616 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4617 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4618 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4622 // test binding single value to sequence type property
4624 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.3.qml"));
4625 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4626 QVERIFY(object != 0);
4627 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4628 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4629 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4630 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4634 // test assigning array to sequence type property in js function
4636 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.4.qml"));
4637 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4638 QVERIFY(object != 0);
4639 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4640 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4641 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4642 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4643 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4644 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4648 // test assigning literal to sequence type property in js function
4650 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.5.qml"));
4651 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4652 QVERIFY(object != 0);
4653 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4654 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4655 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4656 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4657 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4658 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4662 // test assigning single value to sequence type property in js function
4664 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.6.qml"));
4665 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4666 QVERIFY(object != 0);
4667 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4668 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4669 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4670 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4675 // Test that assigning a null object works
4676 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4677 void tst_qdeclarativeecmascript::nullObjectBinding()
4679 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4681 QObject *object = component.create();
4682 QVERIFY(object != 0);
4684 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4689 // Test that bindings don't evaluate once the engine has been destroyed
4690 void tst_qdeclarativeecmascript::deletedEngine()
4692 QDeclarativeEngine *engine = new QDeclarativeEngine;
4693 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4695 QObject *object = component.create();
4696 QVERIFY(object != 0);
4698 QCOMPARE(object->property("a").toInt(), 39);
4699 object->setProperty("b", QVariant(9));
4700 QCOMPARE(object->property("a").toInt(), 117);
4704 QCOMPARE(object->property("a").toInt(), 117);
4705 object->setProperty("b", QVariant(10));
4706 QCOMPARE(object->property("a").toInt(), 117);
4711 // Test the crashing part of QTBUG-9705
4712 void tst_qdeclarativeecmascript::libraryScriptAssert()
4714 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4716 QObject *object = component.create();
4717 QVERIFY(object != 0);
4722 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4724 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4726 QObject *object = component.create();
4727 QVERIFY(object != 0);
4729 QCOMPARE(object->property("test1").toInt(), 10);
4730 QCOMPARE(object->property("test2").toInt(), 11);
4732 object->setProperty("runTest", true);
4734 QCOMPARE(object->property("test1"), QVariant());
4735 QCOMPARE(object->property("test2"), QVariant());
4741 void tst_qdeclarativeecmascript::qtbug_9792()
4743 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4745 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4747 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4748 QVERIFY(object != 0);
4750 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4751 object->basicSignal();
4755 transientErrorsMsgCount = 0;
4756 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4758 object->basicSignal();
4760 qInstallMsgHandler(old);
4762 QCOMPARE(transientErrorsMsgCount, 0);
4767 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4768 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4770 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4772 QObject *o = component.create();
4775 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4776 QVERIFY(nested != 0);
4778 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4781 nested = qvariant_cast<QObject *>(o->property("object"));
4782 QVERIFY(nested == 0);
4784 // If the bug is present, the next line will crash
4788 // Test that we shut down without stupid warnings
4789 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4792 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4794 QObject *o = component.create();
4796 transientErrorsMsgCount = 0;
4797 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4801 qInstallMsgHandler(old);
4803 QCOMPARE(transientErrorsMsgCount, 0);
4808 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4810 QObject *o = component.create();
4812 transientErrorsMsgCount = 0;
4813 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4817 qInstallMsgHandler(old);
4819 QCOMPARE(transientErrorsMsgCount, 0);
4823 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4826 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4828 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4831 QVERIFY(o->objectProperty() != 0);
4833 o->setProperty("runTest", true);
4835 QVERIFY(o->objectProperty() == 0);
4841 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4843 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4846 QVERIFY(o->objectProperty() == 0);
4852 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4854 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4856 QString url = component.url().toString();
4857 QString warning = url + ":4: Unable to assign a function to a property.";
4858 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4860 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4863 QVERIFY(!o->property("a").isValid());
4868 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4870 QFETCH(QString, triggerProperty);
4872 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4873 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4875 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4877 QVERIFY(!o->property("a").isValid());
4879 o->setProperty("aNumber", QVariant(5));
4880 o->setProperty(triggerProperty.toUtf8().constData(), true);
4881 QCOMPARE(o->property("a"), QVariant(50));
4883 o->setProperty("aNumber", QVariant(10));
4884 QCOMPARE(o->property("a"), QVariant(100));
4889 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4891 QTest::addColumn<QString>("triggerProperty");
4893 QTest::newRow("assign to property") << "assignToProperty";
4894 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4896 QTest::newRow("assign to value type") << "assignToValueType";
4898 QTest::newRow("use 'this'") << "assignWithThis";
4899 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4902 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4904 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4905 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4907 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4909 QVERIFY(!o->property("a").isValid());
4911 o->setProperty("assignFuncWithoutReturn", true);
4912 QVERIFY(!o->property("a").isValid());
4914 QString url = component.url().toString();
4915 QString warning = url + ":67: Unable to assign QString to int";
4916 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4917 o->setProperty("assignWrongType", true);
4919 warning = url + ":71: Unable to assign QString to int";
4920 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4921 o->setProperty("assignWrongTypeToValueType", true);
4926 void tst_qdeclarativeecmascript::eval()
4928 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4930 QObject *o = component.create();
4933 QCOMPARE(o->property("test1").toBool(), true);
4934 QCOMPARE(o->property("test2").toBool(), true);
4935 QCOMPARE(o->property("test3").toBool(), true);
4936 QCOMPARE(o->property("test4").toBool(), true);
4937 QCOMPARE(o->property("test5").toBool(), true);
4942 void tst_qdeclarativeecmascript::function()
4944 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4946 QObject *o = component.create();
4949 QCOMPARE(o->property("test1").toBool(), true);
4950 QCOMPARE(o->property("test2").toBool(), true);
4951 QCOMPARE(o->property("test3").toBool(), true);
4956 // Test the "Qt.include" method
4957 void tst_qdeclarativeecmascript::include()
4959 // Non-library relative include
4961 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4962 QObject *o = component.create();
4965 QCOMPARE(o->property("test0").toInt(), 99);
4966 QCOMPARE(o->property("test1").toBool(), true);
4967 QCOMPARE(o->property("test2").toBool(), true);
4968 QCOMPARE(o->property("test2_1").toBool(), true);
4969 QCOMPARE(o->property("test3").toBool(), true);
4970 QCOMPARE(o->property("test3_1").toBool(), true);
4975 // Library relative include
4977 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4978 QObject *o = component.create();
4981 QCOMPARE(o->property("test0").toInt(), 99);
4982 QCOMPARE(o->property("test1").toBool(), true);
4983 QCOMPARE(o->property("test2").toBool(), true);
4984 QCOMPARE(o->property("test2_1").toBool(), true);
4985 QCOMPARE(o->property("test3").toBool(), true);
4986 QCOMPARE(o->property("test3_1").toBool(), true);
4993 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4994 QObject *o = component.create();
4997 QCOMPARE(o->property("test1").toBool(), true);
4998 QCOMPARE(o->property("test2").toBool(), true);
4999 QCOMPARE(o->property("test3").toBool(), true);
5000 QCOMPARE(o->property("test4").toBool(), true);
5001 QCOMPARE(o->property("test5").toBool(), true);
5002 QCOMPARE(o->property("test6").toBool(), true);
5007 // Including file with ".pragma library"
5009 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
5010 QObject *o = component.create();
5012 QCOMPARE(o->property("test1").toInt(), 100);
5019 TestHTTPServer server(8111);
5020 QVERIFY(server.isValid());
5021 server.serveDirectory(TESTDATA(""));
5023 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
5024 QObject *o = component.create();
5027 QTRY_VERIFY(o->property("done").toBool() == true);
5028 QTRY_VERIFY(o->property("done2").toBool() == true);
5030 QCOMPARE(o->property("test1").toBool(), true);
5031 QCOMPARE(o->property("test2").toBool(), true);
5032 QCOMPARE(o->property("test3").toBool(), true);
5033 QCOMPARE(o->property("test4").toBool(), true);
5034 QCOMPARE(o->property("test5").toBool(), true);
5036 QCOMPARE(o->property("test6").toBool(), true);
5037 QCOMPARE(o->property("test7").toBool(), true);
5038 QCOMPARE(o->property("test8").toBool(), true);
5039 QCOMPARE(o->property("test9").toBool(), true);
5040 QCOMPARE(o->property("test10").toBool(), true);
5047 TestHTTPServer server(8111);
5048 QVERIFY(server.isValid());
5049 server.serveDirectory(TESTDATA(""));
5051 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
5052 QObject *o = component.create();
5055 QTRY_VERIFY(o->property("done").toBool() == true);
5057 QCOMPARE(o->property("test1").toBool(), true);
5058 QCOMPARE(o->property("test2").toBool(), true);
5059 QCOMPARE(o->property("test3").toBool(), true);
5065 void tst_qdeclarativeecmascript::signalHandlers()
5067 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
5068 QObject *o = component.create();
5071 QVERIFY(o->property("count").toInt() == 0);
5072 QMetaObject::invokeMethod(o, "testSignalCall");
5073 QCOMPARE(o->property("count").toInt(), 1);
5075 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5076 QCOMPARE(o->property("count").toInt(), 1);
5077 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5079 QVERIFY(o->property("funcCount").toInt() == 0);
5080 QMetaObject::invokeMethod(o, "testSignalConnection");
5081 QCOMPARE(o->property("funcCount").toInt(), 1);
5083 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5084 QCOMPARE(o->property("funcCount").toInt(), 2);
5086 QMetaObject::invokeMethod(o, "testSignalDefined");
5087 QCOMPARE(o->property("definedResult").toBool(), true);
5089 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5090 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5095 void tst_qdeclarativeecmascript::qtbug_10696()
5097 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
5098 QObject *o = component.create();
5103 void tst_qdeclarativeecmascript::qtbug_11606()
5105 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
5106 QObject *o = component.create();
5108 QCOMPARE(o->property("test").toBool(), true);
5112 void tst_qdeclarativeecmascript::qtbug_11600()
5114 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
5115 QObject *o = component.create();
5117 QCOMPARE(o->property("test").toBool(), true);
5121 void tst_qdeclarativeecmascript::qtbug_21864()
5123 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21864.qml"));
5124 QObject *o = component.create();
5126 QCOMPARE(o->property("test").toBool(), true);
5130 // Reading and writing non-scriptable properties should fail
5131 void tst_qdeclarativeecmascript::nonscriptable()
5133 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
5134 QObject *o = component.create();
5136 QCOMPARE(o->property("readOk").toBool(), true);
5137 QCOMPARE(o->property("writeOk").toBool(), true);
5141 // deleteLater() should not be callable from QML
5142 void tst_qdeclarativeecmascript::deleteLater()
5144 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
5145 QObject *o = component.create();
5147 QCOMPARE(o->property("test").toBool(), true);
5151 void tst_qdeclarativeecmascript::in()
5153 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
5154 QObject *o = component.create();
5156 QCOMPARE(o->property("test1").toBool(), true);
5157 QCOMPARE(o->property("test2").toBool(), true);
5161 void tst_qdeclarativeecmascript::typeOf()
5163 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
5165 // These warnings should not happen once QTBUG-21864 is fixed
5166 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5167 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5169 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5170 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5172 QObject *o = component.create();
5175 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5176 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5177 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5178 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5179 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5180 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5181 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5182 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5183 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5184 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5189 void tst_qdeclarativeecmascript::sharedAttachedObject()
5191 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
5192 QObject *o = component.create();
5194 QCOMPARE(o->property("test1").toBool(), true);
5195 QCOMPARE(o->property("test2").toBool(), true);
5200 void tst_qdeclarativeecmascript::objectName()
5202 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
5203 QObject *o = component.create();
5206 QCOMPARE(o->property("test1").toString(), QString("hello"));
5207 QCOMPARE(o->property("test2").toString(), QString("ell"));
5209 o->setObjectName("world");
5211 QCOMPARE(o->property("test1").toString(), QString("world"));
5212 QCOMPARE(o->property("test2").toString(), QString("orl"));
5217 void tst_qdeclarativeecmascript::writeRemovesBinding()
5219 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
5220 QObject *o = component.create();
5223 QCOMPARE(o->property("test").toBool(), true);
5228 // Test bindings assigned to alias properties actually assign to the alias' target
5229 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5231 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
5232 QObject *o = component.create();
5235 QCOMPARE(o->property("test").toBool(), true);
5240 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5241 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5244 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
5245 QObject *o = component.create();
5248 QCOMPARE(o->property("test").toBool(), true);
5254 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
5255 QObject *o = component.create();
5258 QCOMPARE(o->property("test").toBool(), true);
5264 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
5265 QObject *o = component.create();
5268 QCOMPARE(o->property("test").toBool(), true);
5274 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5275 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5278 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
5279 QObject *o = component.create();
5282 QCOMPARE(o->property("test").toBool(), true);
5288 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
5289 QObject *o = component.create();
5292 QCOMPARE(o->property("test").toBool(), true);
5298 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
5299 QObject *o = component.create();
5302 QCOMPARE(o->property("test").toBool(), true);
5308 // Allow an alais to a composite element
5310 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5312 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
5314 QObject *object = component.create();
5315 QVERIFY(object != 0);
5320 void tst_qdeclarativeecmascript::qtbug_20344()
5322 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
5324 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5325 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5327 QObject *object = component.create();
5328 QVERIFY(object != 0);
5333 void tst_qdeclarativeecmascript::revisionErrors()
5336 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
5337 QString url = component.url().toString();
5339 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5340 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5341 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5343 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5344 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5345 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5346 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5347 QVERIFY(object != 0);
5351 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
5352 QString url = component.url().toString();
5354 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5355 // method2, prop2 from MyRevisionedClass not available
5356 // method4, prop4 from MyRevisionedSubclass not available
5357 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5358 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5359 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5360 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5361 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5363 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5364 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5365 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5366 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5367 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5368 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5369 QVERIFY(object != 0);
5373 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5374 QString url = component.url().toString();
5376 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5377 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5378 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5379 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5380 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5381 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5382 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5383 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5384 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5385 QVERIFY(object != 0);
5390 void tst_qdeclarativeecmascript::revision()
5393 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5394 QString url = component.url().toString();
5396 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5397 QVERIFY(object != 0);
5401 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5402 QString url = component.url().toString();
5404 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5405 QVERIFY(object != 0);
5409 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5410 QString url = component.url().toString();
5412 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5413 QVERIFY(object != 0);
5416 // Test that non-root classes can resolve revisioned methods
5418 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5420 QObject *object = component.create();
5421 QVERIFY(object != 0);
5422 QCOMPARE(object->property("test").toReal(), 11.);
5427 void tst_qdeclarativeecmascript::realToInt()
5429 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5430 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5431 QVERIFY(object != 0);
5433 QMetaObject::invokeMethod(object, "test1");
5434 QCOMPARE(object->value(), int(4));
5435 QMetaObject::invokeMethod(object, "test2");
5436 QCOMPARE(object->value(), int(8));
5438 void tst_qdeclarativeecmascript::dynamicString()
5440 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5441 QObject *object = component.create();
5442 QVERIFY(object != 0);
5443 QCOMPARE(object->property("stringProperty").toString(),
5444 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5447 void tst_qdeclarativeecmascript::automaticSemicolon()
5449 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5450 QObject *object = component.create();
5451 QVERIFY(object != 0);
5454 void tst_qdeclarativeecmascript::unaryExpression()
5456 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5457 QObject *object = component.create();
5458 QVERIFY(object != 0);
5461 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5462 void tst_qdeclarativeecmascript::doubleEvaluate()
5464 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5465 QObject *object = component.create();
5466 QVERIFY(object != 0);
5467 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5469 QCOMPARE(wc->count(), 1);
5471 wc->setProperty("x", 9);
5473 QCOMPARE(wc->count(), 2);
5478 static QStringList messages;
5479 static void captureMsgHandler(QtMsgType, const char *msg)
5481 messages.append(QLatin1String(msg));
5484 void tst_qdeclarativeecmascript::nonNotifyable()
5486 QV4Compiler::enableV4(false);
5487 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5488 QV4Compiler::enableV4(true);
5490 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5492 QObject *object = component.create();
5493 qInstallMsgHandler(old);
5495 QVERIFY(object != 0);
5497 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5498 component.url().toString() +
5499 QLatin1String(":5 depends on non-NOTIFYable properties:");
5500 QString expected2 = QLatin1String(" ") +
5501 QLatin1String(object->metaObject()->className()) +
5502 QLatin1String("::value");
5504 QCOMPARE(messages.length(), 2);
5505 QCOMPARE(messages.at(0), expected1);
5506 QCOMPARE(messages.at(1), expected2);
5511 void tst_qdeclarativeecmascript::forInLoop()
5513 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5514 QObject *object = component.create();
5515 QVERIFY(object != 0);
5517 QMetaObject::invokeMethod(object, "listProperty");
5519 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5520 QCOMPARE(r.size(), 3);
5521 QCOMPARE(r[0],QLatin1String("0=obj1"));
5522 QCOMPARE(r[1],QLatin1String("1=obj2"));
5523 QCOMPARE(r[2],QLatin1String("2=obj3"));
5525 //TODO: should test for in loop for other objects (such as QObjects) as well.
5530 // An object the binding depends on is deleted while the binding is still running
5531 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5533 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5534 QObject *object = component.create();
5535 QVERIFY(object != 0);
5539 void tst_qdeclarativeecmascript::qtbug_22679()
5542 object.setStringProperty(QLatin1String("Please work correctly"));
5543 engine.rootContext()->setContextProperty("contextProp", &object);
5545 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5546 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5547 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5549 QObject *o = component.create();
5551 QCOMPARE(warningsSpy.count(), 0);
5555 void tst_qdeclarativeecmascript::qtbug_22843_data()
5557 QTest::addColumn<bool>("library");
5559 QTest::newRow("without .pragma library") << false;
5560 QTest::newRow("with .pragma library") << true;
5563 void tst_qdeclarativeecmascript::qtbug_22843()
5565 QFETCH(bool, library);
5567 QString fileName("qtbug_22843");
5569 fileName += QLatin1String(".library");
5570 fileName += QLatin1String(".qml");
5572 QDeclarativeComponent component(&engine, TEST_FILE(fileName));
5573 QString url = component.url().toString();
5574 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5575 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5577 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5578 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5579 for (int x = 0; x < 3; ++x) {
5580 warningsSpy.clear();
5581 // For libraries, only the first import attempt should produce a
5582 // SyntaxError warning; subsequent component creation should not
5583 // attempt to reload the script.
5584 bool expectSyntaxError = !library || (x == 0);
5585 if (expectSyntaxError)
5586 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5587 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5588 QObject *object = component.create();
5589 QVERIFY(object != 0);
5590 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5596 void tst_qdeclarativeecmascript::switchStatement()
5599 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.1.qml"));
5600 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5601 QVERIFY(object != 0);
5603 // `object->value()' is the number of executed statements
5605 object->setStringProperty("A");
5606 QCOMPARE(object->value(), 5);
5608 object->setStringProperty("S");
5609 QCOMPARE(object->value(), 3);
5611 object->setStringProperty("D");
5612 QCOMPARE(object->value(), 3);
5614 object->setStringProperty("F");
5615 QCOMPARE(object->value(), 4);
5617 object->setStringProperty("something else");
5618 QCOMPARE(object->value(), 1);
5622 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.2.qml"));
5623 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5624 QVERIFY(object != 0);
5626 // `object->value()' is the number of executed statements
5628 object->setStringProperty("A");
5629 QCOMPARE(object->value(), 5);
5631 object->setStringProperty("S");
5632 QCOMPARE(object->value(), 3);
5634 object->setStringProperty("D");
5635 QCOMPARE(object->value(), 3);
5637 object->setStringProperty("F");
5638 QCOMPARE(object->value(), 3);
5640 object->setStringProperty("something else");
5641 QCOMPARE(object->value(), 4);
5645 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.3.qml"));
5646 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5647 QVERIFY(object != 0);
5649 // `object->value()' is the number of executed statements
5651 object->setStringProperty("A");
5652 QCOMPARE(object->value(), 5);
5654 object->setStringProperty("S");
5655 QCOMPARE(object->value(), 3);
5657 object->setStringProperty("D");
5658 QCOMPARE(object->value(), 3);
5660 object->setStringProperty("F");
5661 QCOMPARE(object->value(), 3);
5663 object->setStringProperty("something else");
5664 QCOMPARE(object->value(), 6);
5668 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.4.qml"));
5670 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5671 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5673 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5674 QVERIFY(object != 0);
5676 // `object->value()' is the number of executed statements
5678 object->setStringProperty("A");
5679 QCOMPARE(object->value(), 5);
5681 object->setStringProperty("S");
5682 QCOMPARE(object->value(), 3);
5684 object->setStringProperty("D");
5685 QCOMPARE(object->value(), 3);
5687 object->setStringProperty("F");
5688 QCOMPARE(object->value(), 3);
5690 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5692 object->setStringProperty("something else");
5696 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.5.qml"));
5697 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5698 QVERIFY(object != 0);
5700 // `object->value()' is the number of executed statements
5702 object->setStringProperty("A");
5703 QCOMPARE(object->value(), 1);
5705 object->setStringProperty("S");
5706 QCOMPARE(object->value(), 1);
5708 object->setStringProperty("D");
5709 QCOMPARE(object->value(), 1);
5711 object->setStringProperty("F");
5712 QCOMPARE(object->value(), 1);
5714 object->setStringProperty("something else");
5715 QCOMPARE(object->value(), 1);
5719 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.6.qml"));
5720 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5721 QVERIFY(object != 0);
5723 // `object->value()' is the number of executed statements
5725 object->setStringProperty("A");
5726 QCOMPARE(object->value(), 123);
5728 object->setStringProperty("S");
5729 QCOMPARE(object->value(), 123);
5731 object->setStringProperty("D");
5732 QCOMPARE(object->value(), 321);
5734 object->setStringProperty("F");
5735 QCOMPARE(object->value(), 321);
5737 object->setStringProperty("something else");
5738 QCOMPARE(object->value(), 0);
5742 void tst_qdeclarativeecmascript::withStatement()
5745 QDeclarativeComponent component(&engine, TEST_FILE("withStatement.1.qml"));
5746 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5747 QVERIFY(object != 0);
5749 QCOMPARE(object->value(), 123);
5753 void tst_qdeclarativeecmascript::tryStatement()
5756 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.1.qml"));
5757 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5758 QVERIFY(object != 0);
5760 QCOMPARE(object->value(), 123);
5764 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.2.qml"));
5765 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5766 QVERIFY(object != 0);
5768 QCOMPARE(object->value(), 321);
5772 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.3.qml"));
5773 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5774 QVERIFY(object != 0);
5776 QCOMPARE(object->value(), 1);
5780 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.4.qml"));
5781 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5782 QVERIFY(object != 0);
5784 QCOMPARE(object->value(), 1);
5788 QTEST_MAIN(tst_qdeclarativeecmascript)
5790 #include "tst_qdeclarativeecmascript.moc"