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();
118 void functionErrors();
119 void propertyAssignmentErrors();
120 void signalTriggeredBindings();
121 void listProperties();
122 void exceptionClearsOnReeval();
123 void exceptionSlotProducesWarning();
124 void exceptionBindingProducesWarning();
125 void transientErrors();
126 void shutdownErrors();
127 void compositePropertyType();
129 void undefinedResetsProperty();
130 void listToVariant();
131 void listAssignment();
132 void multiEngineObject();
133 void deletedObject();
134 void attachedPropertyScope();
135 void scriptConnect();
136 void scriptDisconnect();
138 void cppOwnershipReturnValue();
139 void ownershipCustomReturnValue();
140 void qlistqobjectMethods();
141 void strictlyEquals();
143 void numberAssignment();
144 void propertySplicing();
145 void signalWithUnknownTypes();
146 void signalWithJSValueInVariant_data();
147 void signalWithJSValueInVariant();
148 void signalWithJSValueInVariant_twoEngines_data();
149 void signalWithJSValueInVariant_twoEngines();
150 void moduleApi_data();
152 void importScripts_data();
153 void importScripts();
154 void scarceResources();
155 void propertyChangeSlots();
156 void propertyVar_data();
158 void propertyVarCpp();
159 void propertyVarOwnership();
160 void propertyVarImplicitOwnership();
161 void propertyVarReparent();
162 void propertyVarReparentNullContext();
163 void propertyVarCircular();
164 void propertyVarCircular2();
165 void propertyVarInheritance();
166 void propertyVarInheritance2();
167 void elementAssign();
168 void objectPassThroughSignals();
169 void objectConversion();
170 void booleanConversion();
171 void handleReferenceManagement();
173 void readonlyDeclaration();
174 void sequenceConversionRead();
175 void sequenceConversionWrite();
176 void sequenceConversionArray();
177 void sequenceConversionThreads();
178 void sequenceConversionBindings();
179 void sequenceConversionCopy();
180 void assignSequenceTypes();
186 void dynamicCreationCrash();
187 void dynamicCreationOwnership();
189 void nullObjectBinding();
190 void deletedEngine();
191 void libraryScriptAssert();
192 void variantsAssignedUndefined();
194 void qtcreatorbug_1289();
195 void noSpuriousWarningsAtShutdown();
196 void canAssignNullToQObject();
197 void functionAssignment_fromBinding();
198 void functionAssignment_fromJS();
199 void functionAssignment_fromJS_data();
200 void functionAssignmentfromJS_invalid();
207 void nonscriptable();
211 void sharedAttachedObject();
213 void writeRemovesBinding();
214 void aliasBindingsAssignCorrectly();
215 void aliasBindingsOverrideTarget();
216 void aliasWritesOverrideBindings();
217 void aliasToCompositeElement();
219 void dynamicString();
221 void signalHandlers();
222 void doubleEvaluate();
224 void nonNotifyable();
225 void deleteWhileBindingRunning();
226 void callQtInvokables();
227 void invokableObjectArg();
228 void invokableObjectRet();
231 void qtbug_22843_data();
233 void revisionErrors();
236 void automaticSemicolon();
237 void unaryExpression();
238 void switchStatement();
239 void withStatement();
243 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
244 QDeclarativeEngine engine;
247 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
249 void tst_qdeclarativeecmascript::assignBasicTypes()
252 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
253 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
254 QVERIFY(object != 0);
255 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
256 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
257 QCOMPARE(object->stringProperty(), QString("Hello World!"));
258 QCOMPARE(object->uintProperty(), uint(10));
259 QCOMPARE(object->intProperty(), -19);
260 QCOMPARE((float)object->realProperty(), float(23.2));
261 QCOMPARE((float)object->doubleProperty(), float(-19.75));
262 QCOMPARE((float)object->floatProperty(), float(8.5));
263 QCOMPARE(object->colorProperty(), QColor("red"));
264 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
265 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
266 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
267 QCOMPARE(object->pointProperty(), QPoint(99,13));
268 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
269 QCOMPARE(object->sizeProperty(), QSize(99, 13));
270 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
271 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
272 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
273 QCOMPARE(object->boolProperty(), true);
274 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
275 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
276 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
280 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
281 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
282 QVERIFY(object != 0);
283 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
284 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
285 QCOMPARE(object->stringProperty(), QString("Hello World!"));
286 QCOMPARE(object->uintProperty(), uint(10));
287 QCOMPARE(object->intProperty(), -19);
288 QCOMPARE((float)object->realProperty(), float(23.2));
289 QCOMPARE((float)object->doubleProperty(), float(-19.75));
290 QCOMPARE((float)object->floatProperty(), float(8.5));
291 QCOMPARE(object->colorProperty(), QColor("red"));
292 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
293 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
294 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
295 QCOMPARE(object->pointProperty(), QPoint(99,13));
296 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
297 QCOMPARE(object->sizeProperty(), QSize(99, 13));
298 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
299 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
300 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
301 QCOMPARE(object->boolProperty(), true);
302 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
303 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
304 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
309 void tst_qdeclarativeecmascript::idShortcutInvalidates()
312 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
313 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
314 QVERIFY(object != 0);
315 QVERIFY(object->objectProperty() != 0);
316 delete object->objectProperty();
317 QVERIFY(object->objectProperty() == 0);
322 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
323 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
324 QVERIFY(object != 0);
325 QVERIFY(object->objectProperty() != 0);
326 delete object->objectProperty();
327 QVERIFY(object->objectProperty() == 0);
332 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
335 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
336 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
337 QVERIFY(object != 0);
338 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
342 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
343 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
344 QVERIFY(object != 0);
345 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
350 void tst_qdeclarativeecmascript::signalAssignment()
353 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
354 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
355 QVERIFY(object != 0);
356 QCOMPARE(object->string(), QString());
357 emit object->basicSignal();
358 QCOMPARE(object->string(), QString("pass"));
363 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
364 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
365 QVERIFY(object != 0);
366 QCOMPARE(object->string(), QString());
367 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
368 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
373 void tst_qdeclarativeecmascript::methods()
376 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
377 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
378 QVERIFY(object != 0);
379 QCOMPARE(object->methodCalled(), false);
380 QCOMPARE(object->methodIntCalled(), false);
381 emit object->basicSignal();
382 QCOMPARE(object->methodCalled(), true);
383 QCOMPARE(object->methodIntCalled(), false);
388 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
389 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
390 QVERIFY(object != 0);
391 QCOMPARE(object->methodCalled(), false);
392 QCOMPARE(object->methodIntCalled(), false);
393 emit object->basicSignal();
394 QCOMPARE(object->methodCalled(), false);
395 QCOMPARE(object->methodIntCalled(), true);
400 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
401 QObject *object = component.create();
402 QVERIFY(object != 0);
403 QCOMPARE(object->property("test").toInt(), 19);
408 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
409 QObject *object = component.create();
410 QVERIFY(object != 0);
411 QCOMPARE(object->property("test").toInt(), 19);
412 QCOMPARE(object->property("test2").toInt(), 17);
413 QCOMPARE(object->property("test3").toInt(), 16);
418 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
419 QObject *object = component.create();
420 QVERIFY(object != 0);
421 QCOMPARE(object->property("test").toInt(), 9);
426 void tst_qdeclarativeecmascript::bindingLoop()
428 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
429 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
430 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
431 QObject *object = component.create();
432 QVERIFY(object != 0);
436 void tst_qdeclarativeecmascript::basicExpressions_data()
438 QTest::addColumn<QString>("expression");
439 QTest::addColumn<QVariant>("result");
440 QTest::addColumn<bool>("nest");
442 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
443 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
444 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
445 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
446 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
447 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
448 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
449 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
450 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
451 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
452 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
453 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
454 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
455 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
456 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
457 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
458 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
459 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
460 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
463 void tst_qdeclarativeecmascript::basicExpressions()
465 QFETCH(QString, expression);
466 QFETCH(QVariant, result);
472 MyDefaultObject1 default1;
473 MyDefaultObject3 default3;
474 object1.setStringProperty("Object1");
475 object2.setStringProperty("Object2");
476 object3.setStringProperty("Object3");
478 QDeclarativeContext context(engine.rootContext());
479 QDeclarativeContext nestedContext(&context);
481 context.setContextObject(&default1);
482 context.setContextProperty("a", QVariant(1944));
483 context.setContextProperty("b", QVariant("Milk"));
484 context.setContextProperty("object", &object1);
485 context.setContextProperty("objectOverride", &object2);
486 nestedContext.setContextObject(&default3);
487 nestedContext.setContextProperty("b", QVariant("Cow"));
488 nestedContext.setContextProperty("objectOverride", &object3);
489 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
491 MyExpression expr(nest?&nestedContext:&context, expression);
492 QCOMPARE(expr.evaluate(), result);
495 void tst_qdeclarativeecmascript::arrayExpressions()
501 QDeclarativeContext context(engine.rootContext());
502 context.setContextProperty("a", &obj1);
503 context.setContextProperty("b", &obj2);
504 context.setContextProperty("c", &obj3);
506 MyExpression expr(&context, "[a, b, c, 10]");
507 QVariant result = expr.evaluate();
508 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
509 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
510 QCOMPARE(list.count(), 4);
511 QCOMPARE(list.at(0), &obj1);
512 QCOMPARE(list.at(1), &obj2);
513 QCOMPARE(list.at(2), &obj3);
514 QCOMPARE(list.at(3), (QObject *)0);
517 // Tests that modifying a context property will reevaluate expressions
518 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
520 QDeclarativeContext context(engine.rootContext());
523 MyQmlObject *object3 = new MyQmlObject;
525 object1.setStringProperty("Hello");
526 object2.setStringProperty("World");
528 context.setContextProperty("testProp", QVariant(1));
529 context.setContextProperty("testObj", &object1);
530 context.setContextProperty("testObj2", object3);
533 MyExpression expr(&context, "testProp + 1");
534 QCOMPARE(expr.changed, false);
535 QCOMPARE(expr.evaluate(), QVariant(2));
537 context.setContextProperty("testProp", QVariant(2));
538 QCOMPARE(expr.changed, true);
539 QCOMPARE(expr.evaluate(), QVariant(3));
543 MyExpression expr(&context, "testProp + testProp + testProp");
544 QCOMPARE(expr.changed, false);
545 QCOMPARE(expr.evaluate(), QVariant(6));
547 context.setContextProperty("testProp", QVariant(4));
548 QCOMPARE(expr.changed, true);
549 QCOMPARE(expr.evaluate(), QVariant(12));
553 MyExpression expr(&context, "testObj.stringProperty");
554 QCOMPARE(expr.changed, false);
555 QCOMPARE(expr.evaluate(), QVariant("Hello"));
557 context.setContextProperty("testObj", &object2);
558 QCOMPARE(expr.changed, true);
559 QCOMPARE(expr.evaluate(), QVariant("World"));
563 MyExpression expr(&context, "testObj.stringProperty /**/");
564 QCOMPARE(expr.changed, false);
565 QCOMPARE(expr.evaluate(), QVariant("World"));
567 context.setContextProperty("testObj", &object1);
568 QCOMPARE(expr.changed, true);
569 QCOMPARE(expr.evaluate(), QVariant("Hello"));
573 MyExpression expr(&context, "testObj2");
574 QCOMPARE(expr.changed, false);
575 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
581 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
583 QDeclarativeContext context(engine.rootContext());
587 context.setContextProperty("testObj", &object1);
589 object1.setStringProperty(QLatin1String("Hello"));
590 object2.setStringProperty(QLatin1String("Dog"));
591 object3.setStringProperty(QLatin1String("Cat"));
594 MyExpression expr(&context, "testObj.stringProperty");
595 QCOMPARE(expr.changed, false);
596 QCOMPARE(expr.evaluate(), QVariant("Hello"));
598 object1.setStringProperty(QLatin1String("World"));
599 QCOMPARE(expr.changed, true);
600 QCOMPARE(expr.evaluate(), QVariant("World"));
604 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
605 QCOMPARE(expr.changed, false);
606 QCOMPARE(expr.evaluate(), QVariant());
608 object1.setObjectProperty(&object2);
609 QCOMPARE(expr.changed, true);
610 expr.changed = false;
611 QCOMPARE(expr.evaluate(), QVariant("Dog"));
613 object1.setObjectProperty(&object3);
614 QCOMPARE(expr.changed, true);
615 expr.changed = false;
616 QCOMPARE(expr.evaluate(), QVariant("Cat"));
618 object1.setObjectProperty(0);
619 QCOMPARE(expr.changed, true);
620 expr.changed = false;
621 QCOMPARE(expr.evaluate(), QVariant());
623 object1.setObjectProperty(&object3);
624 QCOMPARE(expr.changed, true);
625 expr.changed = false;
626 QCOMPARE(expr.evaluate(), QVariant("Cat"));
628 object3.setStringProperty("Donkey");
629 QCOMPARE(expr.changed, true);
630 expr.changed = false;
631 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
635 void tst_qdeclarativeecmascript::deferredProperties()
637 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
638 MyDeferredObject *object =
639 qobject_cast<MyDeferredObject *>(component.create());
640 QVERIFY(object != 0);
641 QCOMPARE(object->value(), 0);
642 QVERIFY(object->objectProperty() == 0);
643 QVERIFY(object->objectProperty2() != 0);
644 qmlExecuteDeferred(object);
645 QCOMPARE(object->value(), 10);
646 QVERIFY(object->objectProperty() != 0);
647 MyQmlObject *qmlObject =
648 qobject_cast<MyQmlObject *>(object->objectProperty());
649 QVERIFY(qmlObject != 0);
650 QCOMPARE(qmlObject->value(), 10);
651 object->setValue(19);
652 QCOMPARE(qmlObject->value(), 19);
657 // Check errors on deferred properties are correctly emitted
658 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
660 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
661 MyDeferredObject *object =
662 qobject_cast<MyDeferredObject *>(component.create());
663 QVERIFY(object != 0);
664 QCOMPARE(object->value(), 0);
665 QVERIFY(object->objectProperty() == 0);
666 QVERIFY(object->objectProperty2() == 0);
668 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
669 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
671 qmlExecuteDeferred(object);
676 void tst_qdeclarativeecmascript::extensionObjects()
678 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
679 MyExtendedObject *object =
680 qobject_cast<MyExtendedObject *>(component.create());
681 QVERIFY(object != 0);
682 QCOMPARE(object->baseProperty(), 13);
683 QCOMPARE(object->coreProperty(), 9);
684 object->setProperty("extendedProperty", QVariant(11));
685 object->setProperty("baseExtendedProperty", QVariant(92));
686 QCOMPARE(object->coreProperty(), 11);
687 QCOMPARE(object->baseProperty(), 92);
689 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
691 QCOMPARE(nested->baseProperty(), 13);
692 QCOMPARE(nested->coreProperty(), 9);
693 nested->setProperty("extendedProperty", QVariant(11));
694 nested->setProperty("baseExtendedProperty", QVariant(92));
695 QCOMPARE(nested->coreProperty(), 11);
696 QCOMPARE(nested->baseProperty(), 92);
701 void tst_qdeclarativeecmascript::overrideExtensionProperties()
703 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
704 OverrideDefaultPropertyObject *object =
705 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
706 QVERIFY(object != 0);
707 QVERIFY(object->secondProperty() != 0);
708 QVERIFY(object->firstProperty() == 0);
713 void tst_qdeclarativeecmascript::attachedProperties()
716 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
717 QObject *object = component.create();
718 QVERIFY(object != 0);
719 QCOMPARE(object->property("a").toInt(), 19);
720 QCOMPARE(object->property("b").toInt(), 19);
721 QCOMPARE(object->property("c").toInt(), 19);
722 QCOMPARE(object->property("d").toInt(), 19);
727 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
728 QObject *object = component.create();
729 QVERIFY(object != 0);
730 QCOMPARE(object->property("a").toInt(), 26);
731 QCOMPARE(object->property("b").toInt(), 26);
732 QCOMPARE(object->property("c").toInt(), 26);
733 QCOMPARE(object->property("d").toInt(), 26);
739 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
740 QObject *object = component.create();
741 QVERIFY(object != 0);
743 QMetaObject::invokeMethod(object, "writeValue2");
745 MyQmlAttachedObject *attached =
746 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
747 QVERIFY(attached != 0);
749 QCOMPARE(attached->value2(), 9);
754 void tst_qdeclarativeecmascript::enums()
758 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
759 QObject *object = component.create();
760 QVERIFY(object != 0);
762 QCOMPARE(object->property("a").toInt(), 0);
763 QCOMPARE(object->property("b").toInt(), 1);
764 QCOMPARE(object->property("c").toInt(), 2);
765 QCOMPARE(object->property("d").toInt(), 3);
766 QCOMPARE(object->property("e").toInt(), 0);
767 QCOMPARE(object->property("f").toInt(), 1);
768 QCOMPARE(object->property("g").toInt(), 2);
769 QCOMPARE(object->property("h").toInt(), 3);
770 QCOMPARE(object->property("i").toInt(), 19);
771 QCOMPARE(object->property("j").toInt(), 19);
775 // Non-existent enums
777 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
779 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
780 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
781 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
782 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
784 QObject *object = component.create();
785 QVERIFY(object != 0);
786 QCOMPARE(object->property("a").toInt(), 0);
787 QCOMPARE(object->property("b").toInt(), 0);
793 void tst_qdeclarativeecmascript::valueTypeFunctions()
795 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
796 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
798 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
799 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
805 Tests that writing a constant to a property with a binding on it disables the
808 void tst_qdeclarativeecmascript::constantsOverrideBindings()
812 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
813 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
814 QVERIFY(object != 0);
816 QCOMPARE(object->property("c2").toInt(), 0);
817 object->setProperty("c1", QVariant(9));
818 QCOMPARE(object->property("c2").toInt(), 9);
820 emit object->basicSignal();
822 QCOMPARE(object->property("c2").toInt(), 13);
823 object->setProperty("c1", QVariant(8));
824 QCOMPARE(object->property("c2").toInt(), 13);
829 // During construction
831 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
832 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
833 QVERIFY(object != 0);
835 QCOMPARE(object->property("c1").toInt(), 0);
836 QCOMPARE(object->property("c2").toInt(), 10);
837 object->setProperty("c1", QVariant(9));
838 QCOMPARE(object->property("c1").toInt(), 9);
839 QCOMPARE(object->property("c2").toInt(), 10);
847 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
848 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
849 QVERIFY(object != 0);
851 QCOMPARE(object->property("c2").toInt(), 0);
852 object->setProperty("c1", QVariant(9));
853 QCOMPARE(object->property("c2").toInt(), 9);
855 object->setProperty("c2", QVariant(13));
856 QCOMPARE(object->property("c2").toInt(), 13);
857 object->setProperty("c1", QVariant(7));
858 QCOMPARE(object->property("c1").toInt(), 7);
859 QCOMPARE(object->property("c2").toInt(), 13);
867 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
868 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
869 QVERIFY(object != 0);
871 QCOMPARE(object->property("c1").toInt(), 0);
872 QCOMPARE(object->property("c3").toInt(), 10);
873 object->setProperty("c1", QVariant(9));
874 QCOMPARE(object->property("c1").toInt(), 9);
875 QCOMPARE(object->property("c3").toInt(), 10);
882 Tests that assigning a binding to a property that already has a binding causes
883 the original binding to be disabled.
885 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
887 QDeclarativeComponent component(&engine,
888 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
889 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
890 QVERIFY(object != 0);
892 QCOMPARE(object->property("c1").toInt(), 0);
893 QCOMPARE(object->property("c2").toInt(), 0);
894 QCOMPARE(object->property("c3").toInt(), 0);
896 object->setProperty("c1", QVariant(9));
897 QCOMPARE(object->property("c1").toInt(), 9);
898 QCOMPARE(object->property("c2").toInt(), 0);
899 QCOMPARE(object->property("c3").toInt(), 0);
901 object->setProperty("c3", QVariant(8));
902 QCOMPARE(object->property("c1").toInt(), 9);
903 QCOMPARE(object->property("c2").toInt(), 8);
904 QCOMPARE(object->property("c3").toInt(), 8);
910 Access a non-existent attached object.
912 Tests for a regression where this used to crash.
914 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
916 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
918 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
919 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
921 QObject *object = component.create();
922 QVERIFY(object != 0);
927 void tst_qdeclarativeecmascript::scope()
930 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
931 QObject *object = component.create();
932 QVERIFY(object != 0);
934 QCOMPARE(object->property("test1").toInt(), 1);
935 QCOMPARE(object->property("test2").toInt(), 2);
936 QCOMPARE(object->property("test3").toString(), QString("1Test"));
937 QCOMPARE(object->property("test4").toString(), QString("2Test"));
938 QCOMPARE(object->property("test5").toInt(), 1);
939 QCOMPARE(object->property("test6").toInt(), 1);
940 QCOMPARE(object->property("test7").toInt(), 2);
941 QCOMPARE(object->property("test8").toInt(), 2);
942 QCOMPARE(object->property("test9").toInt(), 1);
943 QCOMPARE(object->property("test10").toInt(), 3);
949 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
950 QObject *object = component.create();
951 QVERIFY(object != 0);
953 QCOMPARE(object->property("test1").toInt(), 19);
954 QCOMPARE(object->property("test2").toInt(), 19);
955 QCOMPARE(object->property("test3").toInt(), 14);
956 QCOMPARE(object->property("test4").toInt(), 14);
957 QCOMPARE(object->property("test5").toInt(), 24);
958 QCOMPARE(object->property("test6").toInt(), 24);
964 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
965 QObject *object = component.create();
966 QVERIFY(object != 0);
968 QCOMPARE(object->property("test1").toBool(), true);
969 QCOMPARE(object->property("test2").toBool(), true);
970 QCOMPARE(object->property("test3").toBool(), true);
975 // Signal argument scope
977 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
978 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
979 QVERIFY(object != 0);
981 QCOMPARE(object->property("test").toInt(), 0);
982 QCOMPARE(object->property("test2").toString(), QString());
984 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
986 QCOMPARE(object->property("test").toInt(), 13);
987 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
993 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
994 QObject *object = component.create();
995 QVERIFY(object != 0);
997 QCOMPARE(object->property("test1").toBool(), true);
998 QCOMPARE(object->property("test2").toBool(), true);
1004 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
1005 QObject *object = component.create();
1006 QVERIFY(object != 0);
1008 QCOMPARE(object->property("test").toBool(), true);
1014 // In 4.7, non-library javascript files that had no imports shared the imports of their
1015 // importing context
1016 void tst_qdeclarativeecmascript::importScope()
1018 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1019 QObject *o = component.create();
1022 QCOMPARE(o->property("test").toInt(), 240);
1028 Tests that "any" type passes through a synthesized signal parameter. This
1029 is essentially a test of QDeclarativeMetaType::copy()
1031 void tst_qdeclarativeecmascript::signalParameterTypes()
1033 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1034 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1035 QVERIFY(object != 0);
1037 emit object->basicSignal();
1039 QCOMPARE(object->property("intProperty").toInt(), 10);
1040 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1041 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1042 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1043 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1044 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1050 Test that two JS objects for the same QObject compare as equal.
1052 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1054 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1055 QObject *object = component.create();
1056 QVERIFY(object != 0);
1058 QCOMPARE(object->property("test1").toBool(), true);
1059 QCOMPARE(object->property("test2").toBool(), true);
1060 QCOMPARE(object->property("test3").toBool(), true);
1061 QCOMPARE(object->property("test4").toBool(), true);
1062 QCOMPARE(object->property("test5").toBool(), true);
1068 Confirm bindings and alias properties can coexist.
1070 Tests for a regression where the binding would not reevaluate.
1072 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1074 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1075 QObject *object = component.create();
1076 QVERIFY(object != 0);
1078 QCOMPARE(object->property("c2").toInt(), 3);
1079 QCOMPARE(object->property("c3").toInt(), 3);
1081 object->setProperty("c2", QVariant(19));
1083 QCOMPARE(object->property("c2").toInt(), 19);
1084 QCOMPARE(object->property("c3").toInt(), 19);
1090 Ensure that we can write undefined value to an alias property,
1091 and that the aliased property is reset correctly if possible.
1093 void tst_qdeclarativeecmascript::aliasPropertyReset()
1095 QObject *object = 0;
1097 // test that a manual write (of undefined) to a resettable aliased property succeeds
1098 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1099 object = c1.create();
1100 QVERIFY(object != 0);
1101 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1102 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1103 QMetaObject::invokeMethod(object, "resetAliased");
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1105 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1108 // test that a manual write (of undefined) to a resettable alias property succeeds
1109 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1110 object = c2.create();
1111 QVERIFY(object != 0);
1112 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1113 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1114 QMetaObject::invokeMethod(object, "resetAlias");
1115 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1116 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1119 // test that an alias to a bound property works correctly
1120 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1121 object = c3.create();
1122 QVERIFY(object != 0);
1123 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1124 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1125 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1126 QMetaObject::invokeMethod(object, "resetAlias");
1127 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1128 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1129 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1132 // test that a manual write (of undefined) to a resettable alias property
1133 // whose aliased property's object has been deleted, does not crash.
1134 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1135 object = c4.create();
1136 QVERIFY(object != 0);
1137 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1138 QObject *loader = object->findChild<QObject*>("loader");
1139 QVERIFY(loader != 0);
1141 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1142 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1143 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1144 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1145 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1148 // test that binding an alias property to an undefined value works correctly
1149 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1150 object = c5.create();
1151 QVERIFY(object != 0);
1152 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1155 // test that a manual write (of undefined) to a non-resettable property fails properly
1156 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1157 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1158 QDeclarativeComponent e1(&engine, url);
1159 object = e1.create();
1160 QVERIFY(object != 0);
1161 QCOMPARE(object->property("intAlias").value<int>(), 12);
1162 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1163 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1164 QMetaObject::invokeMethod(object, "resetAlias");
1165 QCOMPARE(object->property("intAlias").value<int>(), 12);
1166 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1170 void tst_qdeclarativeecmascript::dynamicCreation_data()
1172 QTest::addColumn<QString>("method");
1173 QTest::addColumn<QString>("createdName");
1175 QTest::newRow("One") << "createOne" << "objectOne";
1176 QTest::newRow("Two") << "createTwo" << "objectTwo";
1177 QTest::newRow("Three") << "createThree" << "objectThree";
1181 Test using createQmlObject to dynamically generate an item
1182 Also using createComponent is tested.
1184 void tst_qdeclarativeecmascript::dynamicCreation()
1186 QFETCH(QString, method);
1187 QFETCH(QString, createdName);
1189 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1190 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1191 QVERIFY(object != 0);
1193 QMetaObject::invokeMethod(object, method.toUtf8());
1194 QObject *created = object->objectProperty();
1196 QCOMPARE(created->objectName(), createdName);
1202 Tests the destroy function
1204 void tst_qdeclarativeecmascript::dynamicDestruction()
1207 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1208 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1209 QVERIFY(object != 0);
1210 QDeclarativeGuard<QObject> createdQmlObject = 0;
1212 QMetaObject::invokeMethod(object, "create");
1213 createdQmlObject = object->objectProperty();
1214 QVERIFY(createdQmlObject);
1215 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1217 QMetaObject::invokeMethod(object, "killOther");
1218 QVERIFY(createdQmlObject);
1219 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1220 QVERIFY(createdQmlObject);
1221 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1222 if (createdQmlObject) {
1224 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1227 QVERIFY(!createdQmlObject);
1229 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1230 QMetaObject::invokeMethod(object, "killMe");
1233 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1238 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1239 QObject *o = component.create();
1242 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1244 QMetaObject::invokeMethod(o, "create");
1246 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1248 QMetaObject::invokeMethod(o, "destroy");
1250 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1252 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1259 tests that id.toString() works
1261 void tst_qdeclarativeecmascript::objectToString()
1263 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1264 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1265 QVERIFY(object != 0);
1266 QMetaObject::invokeMethod(object, "testToString");
1267 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1268 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1274 tests that id.hasOwnProperty() works
1276 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1278 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1279 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1280 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1281 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1283 QDeclarativeComponent component(&engine, url);
1284 QObject *object = component.create();
1285 QVERIFY(object != 0);
1287 // test QObjects in QML
1288 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1289 QVERIFY(object->property("result").value<bool>() == true);
1290 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1291 QVERIFY(object->property("result").value<bool>() == false);
1293 // now test other types in QML
1294 QObject *child = object->findChild<QObject*>("typeObj");
1295 QVERIFY(child != 0);
1296 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1297 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1298 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1299 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1300 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1301 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1302 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1303 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1304 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1305 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1306 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1307 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1309 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1310 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1311 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1312 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1313 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1314 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1315 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1316 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1317 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1323 Tests bindings that indirectly cause their own deletion work.
1325 This test is best run under valgrind to ensure no invalid memory access occur.
1327 void tst_qdeclarativeecmascript::selfDeletingBinding()
1330 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1331 QObject *object = component.create();
1332 QVERIFY(object != 0);
1333 object->setProperty("triggerDelete", true);
1338 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1339 QObject *object = component.create();
1340 QVERIFY(object != 0);
1341 object->setProperty("triggerDelete", true);
1347 Test that extended object properties can be accessed.
1349 This test a regression where this used to crash. The issue was specificially
1350 for extended objects that did not include a synthesized meta object (so non-root
1351 and no synthesiszed properties).
1353 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1355 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1356 QObject *object = component.create();
1357 QVERIFY(object != 0);
1362 Test file/lineNumbers for binding/Script errors.
1364 void tst_qdeclarativeecmascript::scriptErrors()
1366 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1367 QString url = component.url().toString();
1369 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1370 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1371 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1372 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1373 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1374 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1375 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1376 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1378 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1379 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1380 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1381 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1382 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1383 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1384 QVERIFY(object != 0);
1386 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1387 emit object->basicSignal();
1389 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1390 emit object->anotherBasicSignal();
1392 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1393 emit object->thirdBasicSignal();
1399 Test file/lineNumbers for inline functions.
1401 void tst_qdeclarativeecmascript::functionErrors()
1403 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1404 QString url = component.url().toString();
1406 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1408 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1410 QObject *object = component.create();
1411 QVERIFY(object != 0);
1414 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1415 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1416 url = componentTwo.url().toString();
1417 object = componentTwo.create();
1418 QVERIFY(object != 0);
1420 QString srpname = object->property("srp_name").toString();
1422 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1423 QLatin1String(" is not a function");
1424 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1425 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1430 Test various errors that can occur when assigning a property from script
1432 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1434 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1436 QString url = component.url().toString();
1438 QObject *object = component.create();
1439 QVERIFY(object != 0);
1441 QCOMPARE(object->property("test1").toBool(), true);
1442 QCOMPARE(object->property("test2").toBool(), true);
1448 Test bindings still work when the reeval is triggered from within
1451 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1453 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1454 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1455 QVERIFY(object != 0);
1457 QCOMPARE(object->property("base").toReal(), 50.);
1458 QCOMPARE(object->property("test1").toReal(), 50.);
1459 QCOMPARE(object->property("test2").toReal(), 50.);
1461 object->basicSignal();
1463 QCOMPARE(object->property("base").toReal(), 200.);
1464 QCOMPARE(object->property("test1").toReal(), 200.);
1465 QCOMPARE(object->property("test2").toReal(), 200.);
1467 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1469 QCOMPARE(object->property("base").toReal(), 400.);
1470 QCOMPARE(object->property("test1").toReal(), 400.);
1471 QCOMPARE(object->property("test2").toReal(), 400.);
1477 Test that list properties can be iterated from ECMAScript
1479 void tst_qdeclarativeecmascript::listProperties()
1481 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1482 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1483 QVERIFY(object != 0);
1485 QCOMPARE(object->property("test1").toInt(), 21);
1486 QCOMPARE(object->property("test2").toInt(), 2);
1487 QCOMPARE(object->property("test3").toBool(), true);
1488 QCOMPARE(object->property("test4").toBool(), true);
1493 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1495 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1496 QString url = component.url().toString();
1498 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1500 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1501 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1502 QVERIFY(object != 0);
1504 QCOMPARE(object->property("test").toBool(), false);
1506 MyQmlObject object2;
1507 MyQmlObject object3;
1508 object2.setObjectProperty(&object3);
1509 object->setObjectProperty(&object2);
1511 QCOMPARE(object->property("test").toBool(), true);
1516 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1518 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1519 QString url = component.url().toString();
1521 QString warning = component.url().toString() + ":6: Error: JS exception";
1523 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1524 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1525 QVERIFY(object != 0);
1529 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1531 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1532 QString url = component.url().toString();
1534 QString warning = component.url().toString() + ":5: Error: JS exception";
1536 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1537 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1538 QVERIFY(object != 0);
1542 static int transientErrorsMsgCount = 0;
1543 static void transientErrorsMsgHandler(QtMsgType, const char *)
1545 ++transientErrorsMsgCount;
1548 // Check that transient binding errors are not displayed
1549 void tst_qdeclarativeecmascript::transientErrors()
1552 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1554 transientErrorsMsgCount = 0;
1555 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1557 QObject *object = component.create();
1558 QVERIFY(object != 0);
1560 qInstallMsgHandler(old);
1562 QCOMPARE(transientErrorsMsgCount, 0);
1567 // One binding erroring multiple times, but then resolving
1569 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1571 transientErrorsMsgCount = 0;
1572 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1574 QObject *object = component.create();
1575 QVERIFY(object != 0);
1577 qInstallMsgHandler(old);
1579 QCOMPARE(transientErrorsMsgCount, 0);
1585 // Check that errors during shutdown are minimized
1586 void tst_qdeclarativeecmascript::shutdownErrors()
1588 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1589 QObject *object = component.create();
1590 QVERIFY(object != 0);
1592 transientErrorsMsgCount = 0;
1593 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1597 qInstallMsgHandler(old);
1598 QCOMPARE(transientErrorsMsgCount, 0);
1601 void tst_qdeclarativeecmascript::compositePropertyType()
1603 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1605 QTest::ignoreMessage(QtDebugMsg, "hello world");
1606 QObject *object = qobject_cast<QObject *>(component.create());
1611 void tst_qdeclarativeecmascript::jsObject()
1613 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1614 QObject *object = component.create();
1615 QVERIFY(object != 0);
1617 QCOMPARE(object->property("test").toInt(), 92);
1622 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1625 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1626 QObject *object = component.create();
1627 QVERIFY(object != 0);
1629 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1631 object->setProperty("setUndefined", true);
1633 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1635 object->setProperty("setUndefined", false);
1637 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1642 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1643 QObject *object = component.create();
1644 QVERIFY(object != 0);
1646 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1648 QMetaObject::invokeMethod(object, "doReset");
1650 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1656 // Aliases to variant properties should work
1657 void tst_qdeclarativeecmascript::qtbug_22464()
1659 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1660 QObject *object = component.create();
1661 QVERIFY(object != 0);
1663 QCOMPARE(object->property("test").toBool(), true);
1668 void tst_qdeclarativeecmascript::qtbug_21580()
1670 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
1672 QObject *object = component.create();
1673 QVERIFY(object != 0);
1675 QCOMPARE(object->property("test").toBool(), true);
1681 void tst_qdeclarativeecmascript::bug1()
1683 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1684 QObject *object = component.create();
1685 QVERIFY(object != 0);
1687 QCOMPARE(object->property("test").toInt(), 14);
1689 object->setProperty("a", 11);
1691 QCOMPARE(object->property("test").toInt(), 3);
1693 object->setProperty("b", true);
1695 QCOMPARE(object->property("test").toInt(), 9);
1700 void tst_qdeclarativeecmascript::bug2()
1702 QDeclarativeComponent component(&engine);
1703 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1705 QObject *object = component.create();
1706 QVERIFY(object != 0);
1711 // Don't crash in createObject when the component has errors.
1712 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1714 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1715 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1716 QVERIFY(object != 0);
1718 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1719 QMetaObject::invokeMethod(object, "dontCrash");
1720 QObject *created = object->objectProperty();
1721 QVERIFY(created == 0);
1726 // ownership transferred to JS, ensure that GC runs the dtor
1727 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1730 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1732 // allow the engine to go out of scope too.
1734 QDeclarativeEngine dcoEngine;
1735 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1736 QObject *object = component.create();
1737 QVERIFY(object != 0);
1738 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1739 QVERIFY(mdcdo != 0);
1740 mdcdo->setDtorCount(&dtorCount);
1742 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1743 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1745 // we do this once manually, but it should be done automatically
1746 // when the engine goes out of scope (since it should gc in dtor)
1747 QMetaObject::invokeMethod(object, "performGc");
1750 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1756 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1757 QCOMPARE(dtorCount, expectedDtorCount);
1761 void tst_qdeclarativeecmascript::regExpBug()
1763 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1764 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1765 QVERIFY(object != 0);
1766 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1770 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1772 QString functionSource = QLatin1String("(function(object) { return ") +
1773 QLatin1String(source) + QLatin1String(" })");
1775 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1778 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1779 if (function.IsEmpty())
1781 v8::Handle<v8::Value> args[] = { o };
1782 function->Call(engine->global(), 1, args);
1783 return tc.HasCaught();
1786 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1787 const char *source, v8::Handle<v8::Value> result)
1789 QString functionSource = QLatin1String("(function(object) { return ") +
1790 QLatin1String(source) + QLatin1String(" })");
1792 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1795 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1796 if (function.IsEmpty())
1798 v8::Handle<v8::Value> args[] = { o };
1800 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1805 return value->StrictEquals(result);
1808 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1811 QString functionSource = QLatin1String("(function(object) { return ") +
1812 QLatin1String(source) + QLatin1String(" })");
1814 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1816 return v8::Handle<v8::Value>();
1817 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1818 if (function.IsEmpty())
1819 return v8::Handle<v8::Value>();
1820 v8::Handle<v8::Value> args[] = { o };
1822 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1825 return v8::Handle<v8::Value>();
1829 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1830 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1831 #define EVALUATE(source) evaluate(engine, object, source)
1833 void tst_qdeclarativeecmascript::callQtInvokables()
1835 MyInvokableObject o;
1837 QDeclarativeEngine qmlengine;
1838 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1840 QV8Engine *engine = ep->v8engine();
1842 v8::HandleScope handle_scope;
1843 v8::Context::Scope scope(engine->context());
1845 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1847 // Non-existent methods
1849 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1850 QCOMPARE(o.error(), false);
1851 QCOMPARE(o.invoked(), -1);
1852 QCOMPARE(o.actuals().count(), 0);
1855 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1856 QCOMPARE(o.error(), false);
1857 QCOMPARE(o.invoked(), -1);
1858 QCOMPARE(o.actuals().count(), 0);
1860 // Insufficient arguments
1862 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1863 QCOMPARE(o.error(), false);
1864 QCOMPARE(o.invoked(), -1);
1865 QCOMPARE(o.actuals().count(), 0);
1868 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1869 QCOMPARE(o.error(), false);
1870 QCOMPARE(o.invoked(), -1);
1871 QCOMPARE(o.actuals().count(), 0);
1873 // Excessive arguments
1875 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1876 QCOMPARE(o.error(), false);
1877 QCOMPARE(o.invoked(), 8);
1878 QCOMPARE(o.actuals().count(), 1);
1879 QCOMPARE(o.actuals().at(0), QVariant(10));
1882 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1883 QCOMPARE(o.error(), false);
1884 QCOMPARE(o.invoked(), 9);
1885 QCOMPARE(o.actuals().count(), 2);
1886 QCOMPARE(o.actuals().at(0), QVariant(10));
1887 QCOMPARE(o.actuals().at(1), QVariant(11));
1889 // Test return types
1891 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1892 QCOMPARE(o.error(), false);
1893 QCOMPARE(o.invoked(), 0);
1894 QCOMPARE(o.actuals().count(), 0);
1897 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1898 QCOMPARE(o.error(), false);
1899 QCOMPARE(o.invoked(), 1);
1900 QCOMPARE(o.actuals().count(), 0);
1903 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1904 QCOMPARE(o.error(), false);
1905 QCOMPARE(o.invoked(), 2);
1906 QCOMPARE(o.actuals().count(), 0);
1910 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1911 QVERIFY(!ret.IsEmpty());
1912 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1913 QCOMPARE(o.error(), false);
1914 QCOMPARE(o.invoked(), 3);
1915 QCOMPARE(o.actuals().count(), 0);
1920 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1921 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1922 QCOMPARE(o.error(), false);
1923 QCOMPARE(o.invoked(), 4);
1924 QCOMPARE(o.actuals().count(), 0);
1928 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1929 QCOMPARE(o.error(), false);
1930 QCOMPARE(o.invoked(), 5);
1931 QCOMPARE(o.actuals().count(), 0);
1935 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1936 QVERIFY(ret->IsString());
1937 QCOMPARE(engine->toString(ret), QString("Hello world"));
1938 QCOMPARE(o.error(), false);
1939 QCOMPARE(o.invoked(), 6);
1940 QCOMPARE(o.actuals().count(), 0);
1944 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1945 QCOMPARE(o.error(), false);
1946 QCOMPARE(o.invoked(), 7);
1947 QCOMPARE(o.actuals().count(), 0);
1951 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1952 QCOMPARE(o.error(), false);
1953 QCOMPARE(o.invoked(), 8);
1954 QCOMPARE(o.actuals().count(), 1);
1955 QCOMPARE(o.actuals().at(0), QVariant(94));
1958 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1959 QCOMPARE(o.error(), false);
1960 QCOMPARE(o.invoked(), 8);
1961 QCOMPARE(o.actuals().count(), 1);
1962 QCOMPARE(o.actuals().at(0), QVariant(94));
1965 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1966 QCOMPARE(o.error(), false);
1967 QCOMPARE(o.invoked(), 8);
1968 QCOMPARE(o.actuals().count(), 1);
1969 QCOMPARE(o.actuals().at(0), QVariant(0));
1972 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1973 QCOMPARE(o.error(), false);
1974 QCOMPARE(o.invoked(), 8);
1975 QCOMPARE(o.actuals().count(), 1);
1976 QCOMPARE(o.actuals().at(0), QVariant(0));
1979 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1980 QCOMPARE(o.error(), false);
1981 QCOMPARE(o.invoked(), 8);
1982 QCOMPARE(o.actuals().count(), 1);
1983 QCOMPARE(o.actuals().at(0), QVariant(0));
1986 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1987 QCOMPARE(o.error(), false);
1988 QCOMPARE(o.invoked(), 8);
1989 QCOMPARE(o.actuals().count(), 1);
1990 QCOMPARE(o.actuals().at(0), QVariant(0));
1993 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1994 QCOMPARE(o.error(), false);
1995 QCOMPARE(o.invoked(), 9);
1996 QCOMPARE(o.actuals().count(), 2);
1997 QCOMPARE(o.actuals().at(0), QVariant(122));
1998 QCOMPARE(o.actuals().at(1), QVariant(9));
2001 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2002 QCOMPARE(o.error(), false);
2003 QCOMPARE(o.invoked(), 10);
2004 QCOMPARE(o.actuals().count(), 1);
2005 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2008 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2009 QCOMPARE(o.error(), false);
2010 QCOMPARE(o.invoked(), 10);
2011 QCOMPARE(o.actuals().count(), 1);
2012 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2015 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2016 QCOMPARE(o.error(), false);
2017 QCOMPARE(o.invoked(), 10);
2018 QCOMPARE(o.actuals().count(), 1);
2019 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2022 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2023 QCOMPARE(o.error(), false);
2024 QCOMPARE(o.invoked(), 10);
2025 QCOMPARE(o.actuals().count(), 1);
2026 QCOMPARE(o.actuals().at(0), QVariant(0));
2029 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2030 QCOMPARE(o.error(), false);
2031 QCOMPARE(o.invoked(), 10);
2032 QCOMPARE(o.actuals().count(), 1);
2033 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2036 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2037 QCOMPARE(o.error(), false);
2038 QCOMPARE(o.invoked(), 10);
2039 QCOMPARE(o.actuals().count(), 1);
2040 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2043 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2044 QCOMPARE(o.error(), false);
2045 QCOMPARE(o.invoked(), 11);
2046 QCOMPARE(o.actuals().count(), 1);
2047 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2050 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2051 QCOMPARE(o.error(), false);
2052 QCOMPARE(o.invoked(), 11);
2053 QCOMPARE(o.actuals().count(), 1);
2054 QCOMPARE(o.actuals().at(0), QVariant("19"));
2058 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2059 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2060 QCOMPARE(o.error(), false);
2061 QCOMPARE(o.invoked(), 11);
2062 QCOMPARE(o.actuals().count(), 1);
2063 QCOMPARE(o.actuals().at(0), QVariant(expected));
2067 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2068 QCOMPARE(o.error(), false);
2069 QCOMPARE(o.invoked(), 11);
2070 QCOMPARE(o.actuals().count(), 1);
2071 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2074 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2075 QCOMPARE(o.error(), false);
2076 QCOMPARE(o.invoked(), 11);
2077 QCOMPARE(o.actuals().count(), 1);
2078 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2081 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2082 QCOMPARE(o.error(), false);
2083 QCOMPARE(o.invoked(), 12);
2084 QCOMPARE(o.actuals().count(), 1);
2085 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2088 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2089 QCOMPARE(o.error(), false);
2090 QCOMPARE(o.invoked(), 12);
2091 QCOMPARE(o.actuals().count(), 1);
2092 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2095 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2096 QCOMPARE(o.error(), false);
2097 QCOMPARE(o.invoked(), 12);
2098 QCOMPARE(o.actuals().count(), 1);
2099 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2102 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2103 QCOMPARE(o.error(), false);
2104 QCOMPARE(o.invoked(), 12);
2105 QCOMPARE(o.actuals().count(), 1);
2106 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2109 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2110 QCOMPARE(o.error(), false);
2111 QCOMPARE(o.invoked(), 12);
2112 QCOMPARE(o.actuals().count(), 1);
2113 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2116 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2117 QCOMPARE(o.error(), false);
2118 QCOMPARE(o.invoked(), 12);
2119 QCOMPARE(o.actuals().count(), 1);
2120 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2123 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2124 QCOMPARE(o.error(), false);
2125 QCOMPARE(o.invoked(), 13);
2126 QCOMPARE(o.actuals().count(), 1);
2127 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2130 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2131 QCOMPARE(o.error(), false);
2132 QCOMPARE(o.invoked(), 13);
2133 QCOMPARE(o.actuals().count(), 1);
2134 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2137 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2138 QCOMPARE(o.error(), false);
2139 QCOMPARE(o.invoked(), 13);
2140 QCOMPARE(o.actuals().count(), 1);
2141 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2144 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2145 QCOMPARE(o.error(), false);
2146 QCOMPARE(o.invoked(), 13);
2147 QCOMPARE(o.actuals().count(), 1);
2148 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2151 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2152 QCOMPARE(o.error(), false);
2153 QCOMPARE(o.invoked(), 13);
2154 QCOMPARE(o.actuals().count(), 1);
2155 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2158 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2159 QCOMPARE(o.error(), false);
2160 QCOMPARE(o.invoked(), 14);
2161 QCOMPARE(o.actuals().count(), 1);
2162 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2165 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2166 QCOMPARE(o.error(), false);
2167 QCOMPARE(o.invoked(), 14);
2168 QCOMPARE(o.actuals().count(), 1);
2169 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2172 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2173 QCOMPARE(o.error(), false);
2174 QCOMPARE(o.invoked(), 14);
2175 QCOMPARE(o.actuals().count(), 1);
2176 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2179 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2180 QCOMPARE(o.error(), false);
2181 QCOMPARE(o.invoked(), 14);
2182 QCOMPARE(o.actuals().count(), 1);
2183 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2186 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2187 QCOMPARE(o.error(), false);
2188 QCOMPARE(o.invoked(), 15);
2189 QCOMPARE(o.actuals().count(), 2);
2190 QCOMPARE(o.actuals().at(0), QVariant(4));
2191 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2194 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2195 QCOMPARE(o.error(), false);
2196 QCOMPARE(o.invoked(), 15);
2197 QCOMPARE(o.actuals().count(), 2);
2198 QCOMPARE(o.actuals().at(0), QVariant(8));
2199 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2202 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2203 QCOMPARE(o.error(), false);
2204 QCOMPARE(o.invoked(), 15);
2205 QCOMPARE(o.actuals().count(), 2);
2206 QCOMPARE(o.actuals().at(0), QVariant(3));
2207 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2210 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2211 QCOMPARE(o.error(), false);
2212 QCOMPARE(o.invoked(), 15);
2213 QCOMPARE(o.actuals().count(), 2);
2214 QCOMPARE(o.actuals().at(0), QVariant(44));
2215 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2218 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2219 QCOMPARE(o.error(), false);
2220 QCOMPARE(o.invoked(), -1);
2221 QCOMPARE(o.actuals().count(), 0);
2224 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2225 QCOMPARE(o.error(), false);
2226 QCOMPARE(o.invoked(), 16);
2227 QCOMPARE(o.actuals().count(), 1);
2228 QCOMPARE(o.actuals().at(0), QVariant(10));
2231 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2232 QCOMPARE(o.error(), false);
2233 QCOMPARE(o.invoked(), 17);
2234 QCOMPARE(o.actuals().count(), 2);
2235 QCOMPARE(o.actuals().at(0), QVariant(10));
2236 QCOMPARE(o.actuals().at(1), QVariant(11));
2239 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2240 QCOMPARE(o.error(), false);
2241 QCOMPARE(o.invoked(), 18);
2242 QCOMPARE(o.actuals().count(), 1);
2243 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2246 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2247 QCOMPARE(o.error(), false);
2248 QCOMPARE(o.invoked(), 19);
2249 QCOMPARE(o.actuals().count(), 1);
2250 QCOMPARE(o.actuals().at(0), QVariant(9));
2253 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2254 QCOMPARE(o.error(), false);
2255 QCOMPARE(o.invoked(), 20);
2256 QCOMPARE(o.actuals().count(), 2);
2257 QCOMPARE(o.actuals().at(0), QVariant(10));
2258 QCOMPARE(o.actuals().at(1), QVariant(19));
2261 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2262 QCOMPARE(o.error(), false);
2263 QCOMPARE(o.invoked(), 20);
2264 QCOMPARE(o.actuals().count(), 2);
2265 QCOMPARE(o.actuals().at(0), QVariant(10));
2266 QCOMPARE(o.actuals().at(1), QVariant(13));
2269 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2270 QCOMPARE(o.error(), false);
2271 QCOMPARE(o.invoked(), -3);
2272 QCOMPARE(o.actuals().count(), 1);
2273 QCOMPARE(o.actuals().at(0), QVariant(9));
2276 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2277 QCOMPARE(o.error(), false);
2278 QCOMPARE(o.invoked(), 21);
2279 QCOMPARE(o.actuals().count(), 2);
2280 QCOMPARE(o.actuals().at(0), QVariant(9));
2281 QCOMPARE(o.actuals().at(1), QVariant());
2284 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2285 QCOMPARE(o.error(), false);
2286 QCOMPARE(o.invoked(), 21);
2287 QCOMPARE(o.actuals().count(), 2);
2288 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2289 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2292 // QTBUG-13047 (check that you can pass registered object types as args)
2293 void tst_qdeclarativeecmascript::invokableObjectArg()
2295 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2297 QObject *o = component.create();
2299 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2301 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2306 // QTBUG-13047 (check that you can return registered object types from methods)
2307 void tst_qdeclarativeecmascript::invokableObjectRet()
2309 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2311 QObject *o = component.create();
2313 QCOMPARE(o->property("test").toBool(), true);
2318 void tst_qdeclarativeecmascript::listToVariant()
2320 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2322 MyQmlContainer container;
2324 QDeclarativeContext context(engine.rootContext());
2325 context.setContextObject(&container);
2327 QObject *object = component.create(&context);
2328 QVERIFY(object != 0);
2330 QVariant v = object->property("test");
2331 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2332 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2338 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2339 void tst_qdeclarativeecmascript::listAssignment()
2341 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2342 QObject *obj = component.create();
2343 QCOMPARE(obj->property("list1length").toInt(), 2);
2344 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2345 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2346 QCOMPARE(list1.count(&list1), list2.count(&list2));
2347 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2348 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2353 void tst_qdeclarativeecmascript::multiEngineObject()
2356 obj.setStringProperty("Howdy planet");
2358 QDeclarativeEngine e1;
2359 e1.rootContext()->setContextProperty("thing", &obj);
2360 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2362 QDeclarativeEngine e2;
2363 e2.rootContext()->setContextProperty("thing", &obj);
2364 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2366 QObject *o1 = c1.create();
2367 QObject *o2 = c2.create();
2369 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2370 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2376 // Test that references to QObjects are cleanup when the object is destroyed
2377 void tst_qdeclarativeecmascript::deletedObject()
2379 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2381 QObject *object = component.create();
2383 QCOMPARE(object->property("test1").toBool(), true);
2384 QCOMPARE(object->property("test2").toBool(), true);
2385 QCOMPARE(object->property("test3").toBool(), true);
2386 QCOMPARE(object->property("test4").toBool(), true);
2391 void tst_qdeclarativeecmascript::attachedPropertyScope()
2393 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2395 QObject *object = component.create();
2396 QVERIFY(object != 0);
2398 MyQmlAttachedObject *attached =
2399 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2400 QVERIFY(attached != 0);
2402 QCOMPARE(object->property("value2").toInt(), 0);
2404 attached->emitMySignal();
2406 QCOMPARE(object->property("value2").toInt(), 9);
2411 void tst_qdeclarativeecmascript::scriptConnect()
2414 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2416 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2417 QVERIFY(object != 0);
2419 QCOMPARE(object->property("test").toBool(), false);
2420 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2421 QCOMPARE(object->property("test").toBool(), true);
2427 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2429 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2430 QVERIFY(object != 0);
2432 QCOMPARE(object->property("test").toBool(), false);
2433 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2434 QCOMPARE(object->property("test").toBool(), true);
2440 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2442 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2443 QVERIFY(object != 0);
2445 QCOMPARE(object->property("test").toBool(), false);
2446 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2447 QCOMPARE(object->property("test").toBool(), true);
2453 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2455 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2456 QVERIFY(object != 0);
2458 QCOMPARE(object->methodCalled(), false);
2459 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2460 QCOMPARE(object->methodCalled(), true);
2466 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2468 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2469 QVERIFY(object != 0);
2471 QCOMPARE(object->methodCalled(), false);
2472 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2473 QCOMPARE(object->methodCalled(), true);
2479 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2481 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2482 QVERIFY(object != 0);
2484 QCOMPARE(object->property("test").toInt(), 0);
2485 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2486 QCOMPARE(object->property("test").toInt(), 2);
2492 void tst_qdeclarativeecmascript::scriptDisconnect()
2495 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2497 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2498 QVERIFY(object != 0);
2500 QCOMPARE(object->property("test").toInt(), 0);
2501 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2502 QCOMPARE(object->property("test").toInt(), 1);
2503 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2504 QCOMPARE(object->property("test").toInt(), 2);
2505 emit object->basicSignal();
2506 QCOMPARE(object->property("test").toInt(), 2);
2507 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2508 QCOMPARE(object->property("test").toInt(), 2);
2514 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2516 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2517 QVERIFY(object != 0);
2519 QCOMPARE(object->property("test").toInt(), 0);
2520 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2521 QCOMPARE(object->property("test").toInt(), 1);
2522 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2523 QCOMPARE(object->property("test").toInt(), 2);
2524 emit object->basicSignal();
2525 QCOMPARE(object->property("test").toInt(), 2);
2526 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2527 QCOMPARE(object->property("test").toInt(), 2);
2533 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2535 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2536 QVERIFY(object != 0);
2538 QCOMPARE(object->property("test").toInt(), 0);
2539 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2540 QCOMPARE(object->property("test").toInt(), 1);
2541 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2542 QCOMPARE(object->property("test").toInt(), 2);
2543 emit object->basicSignal();
2544 QCOMPARE(object->property("test").toInt(), 2);
2545 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2546 QCOMPARE(object->property("test").toInt(), 3);
2551 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.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);
2570 class OwnershipObject : public QObject
2574 OwnershipObject() { object = new QObject; }
2576 QPointer<QObject> object;
2579 QObject *getObject() { return object; }
2582 void tst_qdeclarativeecmascript::ownership()
2584 OwnershipObject own;
2585 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2586 context->setContextObject(&own);
2589 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2591 QVERIFY(own.object != 0);
2593 QObject *object = component.create(context);
2595 engine.collectGarbage();
2597 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2599 QVERIFY(own.object == 0);
2604 own.object = new QObject(&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);
2625 class CppOwnershipReturnValue : public QObject
2629 CppOwnershipReturnValue() : value(0) {}
2630 ~CppOwnershipReturnValue() { delete value; }
2632 Q_INVOKABLE QObject *create() {
2633 value = new QObject;
2634 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2638 Q_INVOKABLE MyQmlObject *createQmlObject() {
2639 MyQmlObject *rv = new MyQmlObject;
2644 QPointer<QObject> value;
2648 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2649 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2651 CppOwnershipReturnValue source;
2654 QDeclarativeEngine engine;
2655 engine.rootContext()->setContextProperty("source", &source);
2657 QVERIFY(source.value == 0);
2659 QDeclarativeComponent component(&engine);
2660 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2662 QObject *object = component.create();
2664 QVERIFY(object != 0);
2665 QVERIFY(source.value != 0);
2670 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2672 QVERIFY(source.value != 0);
2676 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2678 CppOwnershipReturnValue source;
2681 QDeclarativeEngine engine;
2682 engine.rootContext()->setContextProperty("source", &source);
2684 QVERIFY(source.value == 0);
2686 QDeclarativeComponent component(&engine);
2687 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2689 QObject *object = component.create();
2691 QVERIFY(object != 0);
2692 QVERIFY(source.value != 0);
2697 engine.collectGarbage();
2698 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2700 QVERIFY(source.value == 0);
2703 class QListQObjectMethodsObject : public QObject
2707 QListQObjectMethodsObject() {
2708 m_objects.append(new MyQmlObject());
2709 m_objects.append(new MyQmlObject());
2712 ~QListQObjectMethodsObject() {
2713 qDeleteAll(m_objects);
2717 QList<QObject *> getObjects() { return m_objects; }
2720 QList<QObject *> m_objects;
2723 // Tests that returning a QList<QObject*> from a method works
2724 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2726 QListQObjectMethodsObject obj;
2727 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2728 context->setContextObject(&obj);
2730 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2732 QObject *object = component.create(context);
2734 QCOMPARE(object->property("test").toInt(), 2);
2735 QCOMPARE(object->property("test2").toBool(), true);
2742 void tst_qdeclarativeecmascript::strictlyEquals()
2744 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2746 QObject *object = component.create();
2747 QVERIFY(object != 0);
2749 QCOMPARE(object->property("test1").toBool(), true);
2750 QCOMPARE(object->property("test2").toBool(), true);
2751 QCOMPARE(object->property("test3").toBool(), true);
2752 QCOMPARE(object->property("test4").toBool(), true);
2753 QCOMPARE(object->property("test5").toBool(), true);
2754 QCOMPARE(object->property("test6").toBool(), true);
2755 QCOMPARE(object->property("test7").toBool(), true);
2756 QCOMPARE(object->property("test8").toBool(), true);
2761 void tst_qdeclarativeecmascript::compiled()
2763 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2765 QObject *object = component.create();
2766 QVERIFY(object != 0);
2768 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2769 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2770 QCOMPARE(object->property("test3").toBool(), true);
2771 QCOMPARE(object->property("test4").toBool(), false);
2772 QCOMPARE(object->property("test5").toBool(), false);
2773 QCOMPARE(object->property("test6").toBool(), true);
2775 QCOMPARE(object->property("test7").toInt(), 185);
2776 QCOMPARE(object->property("test8").toInt(), 167);
2777 QCOMPARE(object->property("test9").toBool(), true);
2778 QCOMPARE(object->property("test10").toBool(), false);
2779 QCOMPARE(object->property("test11").toBool(), false);
2780 QCOMPARE(object->property("test12").toBool(), true);
2782 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2783 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2784 QCOMPARE(object->property("test15").toBool(), false);
2785 QCOMPARE(object->property("test16").toBool(), true);
2787 QCOMPARE(object->property("test17").toInt(), 5);
2788 QCOMPARE(object->property("test18").toReal(), qreal(176));
2789 QCOMPARE(object->property("test19").toInt(), 7);
2790 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2791 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2792 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2793 QCOMPARE(object->property("test23").toBool(), true);
2794 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2795 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2800 // Test that numbers assigned in bindings as strings work consistently
2801 void tst_qdeclarativeecmascript::numberAssignment()
2803 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2805 QObject *object = component.create();
2806 QVERIFY(object != 0);
2808 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2809 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2810 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2811 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2812 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2814 QCOMPARE(object->property("test5"), QVariant((int)7));
2815 QCOMPARE(object->property("test6"), QVariant((int)7));
2816 QCOMPARE(object->property("test7"), QVariant((int)6));
2817 QCOMPARE(object->property("test8"), QVariant((int)6));
2819 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2820 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2821 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2822 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2827 void tst_qdeclarativeecmascript::propertySplicing()
2829 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2831 QObject *object = component.create();
2832 QVERIFY(object != 0);
2834 QCOMPARE(object->property("test").toBool(), true);
2840 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2842 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2844 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2845 QVERIFY(object != 0);
2847 MyQmlObject::MyType type;
2848 type.value = 0x8971123;
2849 emit object->signalWithUnknownType(type);
2851 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2853 QCOMPARE(result.value, type.value);
2859 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2861 QTest::addColumn<QString>("expression");
2862 QTest::addColumn<QString>("compare");
2864 QString compareStrict("(function(a, b) { return a === b; })");
2865 QTest::newRow("true") << "true" << compareStrict;
2866 QTest::newRow("undefined") << "undefined" << compareStrict;
2867 QTest::newRow("null") << "null" << compareStrict;
2868 QTest::newRow("123") << "123" << compareStrict;
2869 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2871 QString comparePropertiesStrict(
2873 " if (typeof b != 'object')"
2875 " var props = Object.getOwnPropertyNames(b);"
2876 " for (var i = 0; i < props.length; ++i) {"
2877 " var p = props[i];"
2878 " return arguments.callee(a[p], b[p]);"
2881 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2882 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2885 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2887 QFETCH(QString, expression);
2888 QFETCH(QString, compare);
2890 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2891 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2892 QVERIFY(object != 0);
2894 QJSValue value = engine.evaluate(expression);
2895 QVERIFY(!engine.hasUncaughtException());
2896 object->setProperty("expression", expression);
2897 object->setProperty("compare", compare);
2898 object->setProperty("pass", false);
2900 emit object->signalWithVariant(QVariant::fromValue(value));
2901 QVERIFY(object->property("pass").toBool());
2904 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2906 signalWithJSValueInVariant_data();
2909 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2911 QFETCH(QString, expression);
2912 QFETCH(QString, compare);
2914 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2915 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2916 QVERIFY(object != 0);
2919 QJSValue value = engine2.evaluate(expression);
2920 QVERIFY(!engine2.hasUncaughtException());
2921 object->setProperty("expression", expression);
2922 object->setProperty("compare", compare);
2923 object->setProperty("pass", false);
2925 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2926 emit object->signalWithVariant(QVariant::fromValue(value));
2927 QVERIFY(!object->property("pass").toBool());
2930 void tst_qdeclarativeecmascript::moduleApi_data()
2932 QTest::addColumn<QUrl>("testfile");
2933 QTest::addColumn<QString>("errorMessage");
2934 QTest::addColumn<QStringList>("warningMessages");
2935 QTest::addColumn<QStringList>("readProperties");
2936 QTest::addColumn<QVariantList>("readExpectedValues");
2937 QTest::addColumn<QStringList>("writeProperties");
2938 QTest::addColumn<QVariantList>("writeValues");
2939 QTest::addColumn<QStringList>("readBackProperties");
2940 QTest::addColumn<QVariantList>("readBackExpectedValues");
2942 QTest::newRow("qobject, register + read + method")
2943 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2946 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2947 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2948 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2954 QTest::newRow("script, register + read")
2955 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2958 << (QStringList() << "scriptTest")
2959 << (QVariantList() << 13)
2965 QTest::newRow("qobject, caching + read")
2966 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2969 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2970 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2976 QTest::newRow("script, caching + read")
2977 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2980 << (QStringList() << "scriptTest")
2981 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2987 QTest::newRow("qobject, writing + readonly constraints")
2988 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2990 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2991 << (QStringList() << "readOnlyProperty" << "writableProperty")
2992 << (QVariantList() << 20 << 50)
2993 << (QStringList() << "firstProperty" << "writableProperty")
2994 << (QVariantList() << 30 << 30)
2995 << (QStringList() << "readOnlyProperty" << "writableProperty")
2996 << (QVariantList() << 20 << 30);
2998 QTest::newRow("script, writing + readonly constraints")
2999 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
3001 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3002 << (QStringList() << "readBack" << "unchanged")
3003 << (QVariantList() << 13 << 42)
3004 << (QStringList() << "firstProperty" << "secondProperty")
3005 << (QVariantList() << 30 << 30)
3006 << (QStringList() << "readBack" << "unchanged")
3007 << (QVariantList() << 30 << 42);
3009 QTest::newRow("qobject module API enum values in JS")
3010 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3013 << (QStringList() << "enumValue" << "enumMethod")
3014 << (QVariantList() << 42 << 30)
3020 QTest::newRow("qobject, invalid major version fail")
3021 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3022 << QString("QDeclarativeComponent: Component is not ready")
3031 QTest::newRow("qobject, invalid minor version fail")
3032 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3033 << QString("QDeclarativeComponent: Component is not ready")
3043 void tst_qdeclarativeecmascript::moduleApi()
3045 QFETCH(QUrl, testfile);
3046 QFETCH(QString, errorMessage);
3047 QFETCH(QStringList, warningMessages);
3048 QFETCH(QStringList, readProperties);
3049 QFETCH(QVariantList, readExpectedValues);
3050 QFETCH(QStringList, writeProperties);
3051 QFETCH(QVariantList, writeValues);
3052 QFETCH(QStringList, readBackProperties);
3053 QFETCH(QVariantList, readBackExpectedValues);
3055 QDeclarativeComponent component(&engine, testfile);
3057 if (!errorMessage.isEmpty())
3058 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3060 if (warningMessages.size())
3061 foreach (const QString &warning, warningMessages)
3062 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3064 QObject *object = component.create();
3065 if (!errorMessage.isEmpty()) {
3066 QVERIFY(object == 0);
3068 QVERIFY(object != 0);
3069 for (int i = 0; i < readProperties.size(); ++i)
3070 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3071 for (int i = 0; i < writeProperties.size(); ++i)
3072 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3073 for (int i = 0; i < readBackProperties.size(); ++i)
3074 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3079 void tst_qdeclarativeecmascript::importScripts_data()
3081 QTest::addColumn<QUrl>("testfile");
3082 QTest::addColumn<QString>("errorMessage");
3083 QTest::addColumn<QStringList>("warningMessages");
3084 QTest::addColumn<QStringList>("propertyNames");
3085 QTest::addColumn<QVariantList>("propertyValues");
3087 QTest::newRow("basic functionality")
3088 << TEST_FILE("jsimport/testImport.qml")
3091 << (QStringList() << QLatin1String("importedScriptStringValue")
3092 << QLatin1String("importedScriptFunctionValue")
3093 << QLatin1String("importedModuleAttachedPropertyValue")
3094 << QLatin1String("importedModuleEnumValue"))
3095 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3100 QTest::newRow("import scoping")
3101 << TEST_FILE("jsimport/testImportScoping.qml")
3104 << (QStringList() << QLatin1String("componentError"))
3105 << (QVariantList() << QVariant(5));
3107 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3108 << TEST_FILE("jsimportfail/failOne.qml")
3110 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3111 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3112 << (QVariantList() << QVariant(QString()));
3114 QTest::newRow("javascript imports in an import should be private to the import scope")
3115 << TEST_FILE("jsimportfail/failTwo.qml")
3117 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3118 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3119 << (QVariantList() << QVariant(QString()));
3121 QTest::newRow("module imports in an import should be private to the import scope")
3122 << TEST_FILE("jsimportfail/failThree.qml")
3124 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3125 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3126 << (QVariantList() << QVariant(false));
3128 QTest::newRow("typenames in an import should be private to the import scope")
3129 << TEST_FILE("jsimportfail/failFour.qml")
3131 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3132 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3133 << (QVariantList() << QVariant(0));
3135 QTest::newRow("import with imports has it's own activation scope")
3136 << TEST_FILE("jsimportfail/failFive.qml")
3138 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3139 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3140 << (QStringList() << QLatin1String("componentError"))
3141 << (QVariantList() << QVariant(0));
3143 QTest::newRow("import pragma library script")
3144 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3147 << (QStringList() << QLatin1String("testValue"))
3148 << (QVariantList() << QVariant(31));
3150 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3151 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3154 << (QStringList() << QLatin1String("testValue"))
3155 << (QVariantList() << QVariant(0));
3157 QTest::newRow("import pragma library script which has an import")
3158 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3161 << (QStringList() << QLatin1String("testValue"))
3162 << (QVariantList() << QVariant(55));
3164 QTest::newRow("import pragma library script which has a pragma library import")
3165 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3168 << (QStringList() << QLatin1String("testValue"))
3169 << (QVariantList() << QVariant(18));
3172 void tst_qdeclarativeecmascript::importScripts()
3174 QFETCH(QUrl, testfile);
3175 QFETCH(QString, errorMessage);
3176 QFETCH(QStringList, warningMessages);
3177 QFETCH(QStringList, propertyNames);
3178 QFETCH(QVariantList, propertyValues);
3180 QDeclarativeComponent component(&engine, testfile);
3182 if (!errorMessage.isEmpty())
3183 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3185 if (warningMessages.size())
3186 foreach (const QString &warning, warningMessages)
3187 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3189 QObject *object = component.create();
3190 if (!errorMessage.isEmpty()) {
3191 QVERIFY(object == 0);
3193 QVERIFY(object != 0);
3194 for (int i = 0; i < propertyNames.size(); ++i)
3195 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3200 void tst_qdeclarativeecmascript::scarceResources()
3202 QPixmap origPixmap(100, 100);
3203 origPixmap.fill(Qt::blue);
3205 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3206 ScarceResourceObject *eo = 0;
3207 QObject *object = 0;
3209 // in the following three cases, the instance created from the component
3210 // has a property which is a copy of the scarce resource; hence, the
3211 // resource should NOT be detached prior to deletion of the object instance,
3212 // unless the resource is destroyed explicitly.
3213 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3214 object = component.create();
3215 QVERIFY(object != 0);
3216 QVERIFY(object->property("scarceResourceCopy").isValid());
3217 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3218 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3219 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3220 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3223 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3224 object = componentTwo.create();
3225 QVERIFY(object != 0);
3226 QVERIFY(object->property("scarceResourceCopy").isValid());
3227 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3228 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3229 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3230 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3233 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3234 object = componentThree.create();
3235 QVERIFY(object != 0);
3236 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3237 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3238 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3239 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3242 // in the following three cases, no other copy should exist in memory,
3243 // and so it should be detached (unless explicitly preserved).
3244 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3245 object = componentFour.create();
3246 QVERIFY(object != 0);
3247 QVERIFY(object->property("scarceResourceTest").isValid());
3248 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3249 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3250 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3251 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3254 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3255 object = componentFive.create();
3256 QVERIFY(object != 0);
3257 QVERIFY(object->property("scarceResourceTest").isValid());
3258 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3259 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3260 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3261 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3264 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3265 object = componentSix.create();
3266 QVERIFY(object != 0);
3267 QVERIFY(object->property("scarceResourceTest").isValid());
3268 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3269 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3270 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3271 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3274 // test that scarce resources are handled correctly for imports
3275 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3276 object = componentSeven.create();
3277 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3278 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3281 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3282 object = componentEight.create();
3283 QVERIFY(object != 0);
3284 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3285 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3288 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3289 object = componentNine.create();
3290 QVERIFY(object != 0);
3291 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3292 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3293 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3294 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3295 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3296 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3299 // test that scarce resources are handled properly in signal invocation
3300 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3301 object = componentTen.create();
3302 QVERIFY(object != 0);
3303 QObject *srsc = object->findChild<QObject*>("srsc");
3305 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3306 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3307 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3308 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3309 QMetaObject::invokeMethod(srsc, "testSignal");
3310 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3311 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3312 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3313 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3314 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3315 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3316 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3317 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3318 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3319 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3322 // test that scarce resources are handled properly from js functions in qml files
3323 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3324 object = componentEleven.create();
3325 QVERIFY(object != 0);
3326 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3327 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3328 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3329 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3330 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3331 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3332 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3333 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3334 QMetaObject::invokeMethod(object, "releaseScarceResource");
3335 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3336 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3337 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3338 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3341 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3342 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3343 object = componentTwelve.create();
3344 QVERIFY(object != 0);
3345 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3346 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3347 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3348 QString srp_name = object->property("srp_name").toString();
3349 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3350 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3351 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3352 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3353 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3354 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3355 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3359 void tst_qdeclarativeecmascript::propertyChangeSlots()
3361 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3362 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3363 QObject *object = component.create();
3364 QVERIFY(object != 0);
3367 // ensure that invalid property names fail properly.
3368 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3369 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3370 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3371 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3372 object = e1.create();
3373 QVERIFY(object == 0);
3376 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3377 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3378 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3379 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3380 object = e2.create();
3381 QVERIFY(object == 0);
3384 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3385 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3386 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3387 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3388 object = e3.create();
3389 QVERIFY(object == 0);
3392 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3393 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3394 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3395 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3396 object = e4.create();
3397 QVERIFY(object == 0);
3401 void tst_qdeclarativeecmascript::propertyVar_data()
3403 QTest::addColumn<QUrl>("qmlFile");
3406 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3407 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3408 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3409 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3410 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3411 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3412 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3413 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3414 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3417 void tst_qdeclarativeecmascript::propertyVar()
3419 QFETCH(QUrl, qmlFile);
3421 QDeclarativeComponent component(&engine, qmlFile);
3422 QObject *object = component.create();
3423 QVERIFY(object != 0);
3425 QCOMPARE(object->property("test").toBool(), true);
3430 // Tests that we can write QVariant values to var properties from C++
3431 void tst_qdeclarativeecmascript::propertyVarCpp()
3433 QObject *object = 0;
3435 // ensure that writing to and reading from a var property from cpp works as required.
3436 // Literal values stored in var properties can be read and written as QVariants
3437 // of a specific type, whereas object values are read as QVariantMaps.
3438 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3439 object = component.create();
3440 QVERIFY(object != 0);
3441 // assign int to property var that currently has int assigned
3442 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3443 QCOMPARE(object->property("varBound"), QVariant(15));
3444 QCOMPARE(object->property("intBound"), QVariant(15));
3445 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3446 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3447 // assign string to property var that current has bool assigned
3448 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3449 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3450 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3451 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3452 // now enforce behaviour when accessing JavaScript objects from cpp.
3453 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3457 static void gc(QDeclarativeEngine &engine)
3459 engine.collectGarbage();
3460 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3463 void tst_qdeclarativeecmascript::propertyVarOwnership()
3465 // Referenced JS objects are not collected
3467 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3468 QObject *object = component.create();
3469 QVERIFY(object != 0);
3470 QCOMPARE(object->property("test").toBool(), false);
3471 QMetaObject::invokeMethod(object, "runTest");
3472 QCOMPARE(object->property("test").toBool(), true);
3475 // Referenced JS objects are not collected
3477 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3478 QObject *object = component.create();
3479 QVERIFY(object != 0);
3480 QCOMPARE(object->property("test").toBool(), false);
3481 QMetaObject::invokeMethod(object, "runTest");
3482 QCOMPARE(object->property("test").toBool(), true);
3485 // Qt objects are not collected until they've been dereferenced
3487 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3488 QObject *object = component.create();
3489 QVERIFY(object != 0);
3491 QCOMPARE(object->property("test2").toBool(), false);
3492 QCOMPARE(object->property("test2").toBool(), false);
3494 QMetaObject::invokeMethod(object, "runTest");
3495 QCOMPARE(object->property("test1").toBool(), true);
3497 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3498 QVERIFY(!referencedObject.isNull());
3500 QVERIFY(!referencedObject.isNull());
3502 QMetaObject::invokeMethod(object, "runTest2");
3503 QCOMPARE(object->property("test2").toBool(), true);
3505 QVERIFY(referencedObject.isNull());
3509 // Self reference does not prevent Qt object collection
3511 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3512 QObject *object = component.create();
3513 QVERIFY(object != 0);
3515 QCOMPARE(object->property("test").toBool(), true);
3517 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3518 QVERIFY(!referencedObject.isNull());
3520 QVERIFY(!referencedObject.isNull());
3522 QMetaObject::invokeMethod(object, "runTest");
3524 QVERIFY(referencedObject.isNull());
3530 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3532 // The childObject has a reference to a different QObject. We want to ensure
3533 // that the different item will not be cleaned up until required. IE, the childObject
3534 // has implicit ownership of the constructed QObject.
3535 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3536 QObject *object = component.create();
3537 QVERIFY(object != 0);
3538 QMetaObject::invokeMethod(object, "assignCircular");
3539 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3540 QObject *rootObject = object->property("vp").value<QObject*>();
3541 QVERIFY(rootObject != 0);
3542 QObject *childObject = rootObject->findChild<QObject*>("text");
3543 QVERIFY(childObject != 0);
3544 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3545 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3546 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3547 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3548 QVERIFY(!qobjectGuard.isNull());
3549 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3550 QVERIFY(!qobjectGuard.isNull());
3551 QMetaObject::invokeMethod(object, "deassignCircular");
3552 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3553 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3557 void tst_qdeclarativeecmascript::propertyVarReparent()
3559 // ensure that nothing breaks if we re-parent objects
3560 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3561 QObject *object = component.create();
3562 QVERIFY(object != 0);
3563 QMetaObject::invokeMethod(object, "assignVarProp");
3564 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3565 QObject *rect = object->property("vp").value<QObject*>();
3566 QObject *text = rect->findChild<QObject*>("textOne");
3567 QObject *text2 = rect->findChild<QObject*>("textTwo");
3568 QWeakPointer<QObject> rectGuard(rect);
3569 QWeakPointer<QObject> textGuard(text);
3570 QWeakPointer<QObject> text2Guard(text2);
3571 QVERIFY(!rectGuard.isNull());
3572 QVERIFY(!textGuard.isNull());
3573 QVERIFY(!text2Guard.isNull());
3574 QCOMPARE(text->property("textCanary").toInt(), 11);
3575 QCOMPARE(text2->property("textCanary").toInt(), 12);
3576 // now construct an image which we will reparent.
3577 QMetaObject::invokeMethod(text2, "constructQObject");
3578 QObject *image = text2->property("vp").value<QObject*>();
3579 QWeakPointer<QObject> imageGuard(image);
3580 QVERIFY(!imageGuard.isNull());
3581 QCOMPARE(image->property("imageCanary").toInt(), 13);
3582 // now reparent the "Image" object (currently, it has JS ownership)
3583 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3584 QMetaObject::invokeMethod(text2, "deassignVp");
3585 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3586 QCOMPARE(text->property("textCanary").toInt(), 11);
3587 QCOMPARE(text2->property("textCanary").toInt(), 22);
3588 QVERIFY(!imageGuard.isNull()); // should still be alive.
3589 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3590 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3591 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3592 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3596 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3598 // sometimes reparenting can cause problems
3599 // (eg, if the ctxt is collected, varproperties are no longer available)
3600 // this test ensures that no crash occurs in that situation.
3601 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3602 QObject *object = component.create();
3603 QVERIFY(object != 0);
3604 QMetaObject::invokeMethod(object, "assignVarProp");
3605 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3606 QObject *rect = object->property("vp").value<QObject*>();
3607 QObject *text = rect->findChild<QObject*>("textOne");
3608 QObject *text2 = rect->findChild<QObject*>("textTwo");
3609 QWeakPointer<QObject> rectGuard(rect);
3610 QWeakPointer<QObject> textGuard(text);
3611 QWeakPointer<QObject> text2Guard(text2);
3612 QVERIFY(!rectGuard.isNull());
3613 QVERIFY(!textGuard.isNull());
3614 QVERIFY(!text2Guard.isNull());
3615 QCOMPARE(text->property("textCanary").toInt(), 11);
3616 QCOMPARE(text2->property("textCanary").toInt(), 12);
3617 // now construct an image which we will reparent.
3618 QMetaObject::invokeMethod(text2, "constructQObject");
3619 QObject *image = text2->property("vp").value<QObject*>();
3620 QWeakPointer<QObject> imageGuard(image);
3621 QVERIFY(!imageGuard.isNull());
3622 QCOMPARE(image->property("imageCanary").toInt(), 13);
3623 // now reparent the "Image" object (currently, it has JS ownership)
3624 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3625 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3626 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3627 QVERIFY(!imageGuard.isNull()); // should still be alive.
3628 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3630 QVERIFY(imageGuard.isNull()); // should now be dead.
3633 void tst_qdeclarativeecmascript::propertyVarCircular()
3635 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3636 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3637 QObject *object = component.create();
3638 QVERIFY(object != 0);
3639 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3640 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3641 QCOMPARE(object->property("canaryInt"), QVariant(5));
3642 QVariant canaryResourceVariant = object->property("canaryResource");
3643 QVERIFY(canaryResourceVariant.isValid());
3644 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3645 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3646 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3647 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3648 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3649 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3650 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3651 QCOMPARE(object->property("canaryInt"), QVariant(2));
3652 QCOMPARE(object->property("canaryResource"), QVariant(1));
3653 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3657 void tst_qdeclarativeecmascript::propertyVarCircular2()
3659 // track deletion of JS-owned parent item with Cpp-owned child
3660 // where the child has a var property referencing its parent.
3661 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3662 QObject *object = component.create();
3663 QVERIFY(object != 0);
3664 QMetaObject::invokeMethod(object, "assignCircular");
3665 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3666 QObject *rootObject = object->property("vp").value<QObject*>();
3667 QVERIFY(rootObject != 0);
3668 QObject *childObject = rootObject->findChild<QObject*>("text");
3669 QVERIFY(childObject != 0);
3670 QWeakPointer<QObject> rootObjectTracker(rootObject);
3671 QVERIFY(!rootObjectTracker.isNull());
3672 QWeakPointer<QObject> childObjectTracker(childObject);
3673 QVERIFY(!childObjectTracker.isNull());
3675 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3676 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3677 QMetaObject::invokeMethod(object, "deassignCircular");
3678 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3679 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3680 QVERIFY(childObjectTracker.isNull()); // should have been collected
3684 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3686 *(int*)(parameter) += 1;
3687 qPersistentDispose(object);
3690 void tst_qdeclarativeecmascript::propertyVarInheritance()
3692 int propertyVarWeakRefCallbackCount = 0;
3694 // enforce behaviour regarding element inheritance - ensure handle disposal.
3695 // The particular component under test here has a chain of references.
3696 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3697 QObject *object = component.create();
3698 QVERIFY(object != 0);
3699 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3700 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3701 // we want to be able to track when the varProperties array of the last metaobject is disposed
3702 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3703 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*>();
3704 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3705 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3706 v8::Persistent<v8::Value> icoCanaryHandle;
3707 v8::Persistent<v8::Value> ccoCanaryHandle;
3710 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3711 // public function which can return us a handle to something in the varProperties array.
3712 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3713 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3714 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3715 // as the varproperties array of each vmemo still references the resource.
3716 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3717 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3719 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3721 // now we deassign the var prop, which should trigger collection of item subtrees.
3722 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3723 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3724 // ensure that there are only weak handles to the underlying varProperties array remaining.
3726 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3728 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3729 // to what remains are weak, all varProperties arrays must have been collected.
3732 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3734 int propertyVarWeakRefCallbackCount = 0;
3736 // The particular component under test here does NOT have a chain of references; the
3737 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3738 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3739 QObject *object = component.create();
3740 QVERIFY(object != 0);
3741 QMetaObject::invokeMethod(object, "assignCircular");
3742 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3743 QObject *rootObject = object->property("vp").value<QObject*>();
3744 QVERIFY(rootObject != 0);
3745 QObject *childObject = rootObject->findChild<QObject*>("text");
3746 QVERIFY(childObject != 0);
3747 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3748 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3749 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3752 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3753 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3754 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3756 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3757 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3759 QMetaObject::invokeMethod(object, "deassignCircular");
3760 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3761 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3765 // Ensure that QObject type conversion works on binding assignment
3766 void tst_qdeclarativeecmascript::elementAssign()
3768 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3770 QObject *object = component.create();
3771 QVERIFY(object != 0);
3773 QCOMPARE(object->property("test").toBool(), true);
3779 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3781 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3783 QObject *object = component.create();
3784 QVERIFY(object != 0);
3786 QCOMPARE(object->property("test").toBool(), true);
3792 void tst_qdeclarativeecmascript::objectConversion()
3794 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3796 QObject *object = component.create();
3797 QVERIFY(object != 0);
3799 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3800 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3807 void tst_qdeclarativeecmascript::booleanConversion()
3809 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3811 QObject *object = component.create();
3812 QVERIFY(object != 0);
3814 QCOMPARE(object->property("test_true1").toBool(), true);
3815 QCOMPARE(object->property("test_true2").toBool(), true);
3816 QCOMPARE(object->property("test_true3").toBool(), true);
3817 QCOMPARE(object->property("test_true4").toBool(), true);
3818 QCOMPARE(object->property("test_true5").toBool(), true);
3820 QCOMPARE(object->property("test_false1").toBool(), false);
3821 QCOMPARE(object->property("test_false2").toBool(), false);
3822 QCOMPARE(object->property("test_false3").toBool(), false);
3827 void tst_qdeclarativeecmascript::handleReferenceManagement()
3832 // Linear QObject reference
3833 QDeclarativeEngine hrmEngine;
3834 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3835 QObject *object = component.create();
3836 QVERIFY(object != 0);
3837 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3838 cro->setDtorCount(&dtorCount);
3839 QMetaObject::invokeMethod(object, "createReference");
3841 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3843 hrmEngine.collectGarbage();
3844 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3845 QCOMPARE(dtorCount, 3);
3850 // Circular QObject reference
3851 QDeclarativeEngine hrmEngine;
3852 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3853 QObject *object = component.create();
3854 QVERIFY(object != 0);
3855 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3856 cro->setDtorCount(&dtorCount);
3857 QMetaObject::invokeMethod(object, "circularReference");
3859 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3861 hrmEngine.collectGarbage();
3862 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3863 QCOMPARE(dtorCount, 3);
3868 // Linear handle reference
3869 QDeclarativeEngine hrmEngine;
3870 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3871 QObject *object = component.create();
3872 QVERIFY(object != 0);
3873 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3875 crh->setDtorCount(&dtorCount);
3876 QMetaObject::invokeMethod(object, "createReference");
3877 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3878 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3879 QVERIFY(first != 0);
3880 QVERIFY(second != 0);
3881 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3882 // now we have to reparent second and make second owned by JS.
3883 second->setParent(0);
3884 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3886 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3888 hrmEngine.collectGarbage();
3889 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3890 QCOMPARE(dtorCount, 3);
3895 // Circular handle reference
3896 QDeclarativeEngine hrmEngine;
3897 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3898 QObject *object = component.create();
3899 QVERIFY(object != 0);
3900 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3902 crh->setDtorCount(&dtorCount);
3903 QMetaObject::invokeMethod(object, "circularReference");
3904 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3905 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3906 QVERIFY(first != 0);
3907 QVERIFY(second != 0);
3908 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3909 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3910 // now we have to reparent and change ownership.
3911 first->setParent(0);
3912 second->setParent(0);
3913 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3914 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3916 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3918 hrmEngine.collectGarbage();
3919 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3920 QCOMPARE(dtorCount, 3);
3925 // multiple engine interaction - linear reference
3926 QDeclarativeEngine hrmEngine1;
3927 QDeclarativeEngine hrmEngine2;
3928 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3929 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3930 QObject *object1 = component1.create();
3931 QObject *object2 = component2.create();
3932 QVERIFY(object1 != 0);
3933 QVERIFY(object2 != 0);
3934 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3935 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3938 crh1->setDtorCount(&dtorCount);
3939 crh2->setDtorCount(&dtorCount);
3940 QMetaObject::invokeMethod(object1, "createReference");
3941 QMetaObject::invokeMethod(object2, "createReference");
3942 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3943 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3944 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3945 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3946 QVERIFY(first1 != 0);
3947 QVERIFY(second1 != 0);
3948 QVERIFY(first2 != 0);
3949 QVERIFY(second2 != 0);
3950 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3951 // now we have to reparent second2 and make second2 owned by JS.
3952 second2->setParent(0);
3953 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3955 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3956 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3959 hrmEngine1.collectGarbage();
3960 hrmEngine2.collectGarbage();
3961 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3962 QCOMPARE(dtorCount, 6);
3967 // multiple engine interaction - circular reference
3968 QDeclarativeEngine hrmEngine1;
3969 QDeclarativeEngine hrmEngine2;
3970 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3971 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3972 QObject *object1 = component1.create();
3973 QObject *object2 = component2.create();
3974 QVERIFY(object1 != 0);
3975 QVERIFY(object2 != 0);
3976 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3977 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3980 crh1->setDtorCount(&dtorCount);
3981 crh2->setDtorCount(&dtorCount);
3982 QMetaObject::invokeMethod(object1, "createReference");
3983 QMetaObject::invokeMethod(object2, "createReference");
3984 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3985 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3986 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3987 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3988 QVERIFY(first1 != 0);
3989 QVERIFY(second1 != 0);
3990 QVERIFY(first2 != 0);
3991 QVERIFY(second2 != 0);
3992 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3993 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3994 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3995 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3996 // now we have to reparent and change ownership to JS.
3997 first1->setParent(0);
3998 second1->setParent(0);
3999 first2->setParent(0);
4000 second2->setParent(0);
4001 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4002 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4003 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4004 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4006 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4007 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4010 hrmEngine1.collectGarbage();
4011 hrmEngine2.collectGarbage();
4012 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4013 QCOMPARE(dtorCount, 6);
4018 // multiple engine interaction - linear reference with engine deletion
4019 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4020 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4021 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4022 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4023 QObject *object1 = component1.create();
4024 QObject *object2 = component2.create();
4025 QVERIFY(object1 != 0);
4026 QVERIFY(object2 != 0);
4027 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4028 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4031 crh1->setDtorCount(&dtorCount);
4032 crh2->setDtorCount(&dtorCount);
4033 QMetaObject::invokeMethod(object1, "createReference");
4034 QMetaObject::invokeMethod(object2, "createReference");
4035 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4036 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4037 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4038 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4039 QVERIFY(first1 != 0);
4040 QVERIFY(second1 != 0);
4041 QVERIFY(first2 != 0);
4042 QVERIFY(second2 != 0);
4043 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4044 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4045 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4046 // now we have to reparent and change ownership to JS.
4047 first1->setParent(crh1);
4048 second1->setParent(0);
4049 first2->setParent(0);
4050 second2->setParent(0);
4051 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4052 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4053 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4055 QCOMPARE(dtorCount, 0);
4058 QCOMPARE(dtorCount, 0);
4061 hrmEngine1->collectGarbage();
4062 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4063 QCOMPARE(dtorCount, 6);
4068 void tst_qdeclarativeecmascript::stringArg()
4070 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4071 QObject *object = component.create();
4072 QVERIFY(object != 0);
4073 QMetaObject::invokeMethod(object, "success");
4074 QVERIFY(object->property("returnValue").toBool());
4076 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4077 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4078 QMetaObject::invokeMethod(object, "failure");
4079 QVERIFY(object->property("returnValue").toBool());
4084 void tst_qdeclarativeecmascript::readonlyDeclaration()
4086 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4088 QObject *object = component.create();
4089 QVERIFY(object != 0);
4091 QCOMPARE(object->property("test").toBool(), true);
4096 Q_DECLARE_METATYPE(QList<int>)
4097 Q_DECLARE_METATYPE(QList<qreal>)
4098 Q_DECLARE_METATYPE(QList<bool>)
4099 Q_DECLARE_METATYPE(QList<QString>)
4100 Q_DECLARE_METATYPE(QList<QUrl>)
4101 void tst_qdeclarativeecmascript::sequenceConversionRead()
4104 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4105 QDeclarativeComponent component(&engine, qmlFile);
4106 QObject *object = component.create();
4107 QVERIFY(object != 0);
4108 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4111 QMetaObject::invokeMethod(object, "readSequences");
4112 QList<int> intList; intList << 1 << 2 << 3 << 4;
4113 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4114 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4115 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4116 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4117 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4118 QList<bool> boolList; boolList << true << false << true << false;
4119 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4120 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4121 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4122 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4123 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4124 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4125 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4126 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4127 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4128 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4129 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4131 QMetaObject::invokeMethod(object, "readSequenceElements");
4132 QCOMPARE(object->property("intVal").toInt(), 2);
4133 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4134 QCOMPARE(object->property("boolVal").toBool(), false);
4135 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4136 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4137 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4139 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4140 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4142 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4143 QDeclarativeProperty seqProp(seq, "intListProperty");
4144 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4145 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4146 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4148 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4149 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4155 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4156 QDeclarativeComponent component(&engine, qmlFile);
4157 QObject *object = component.create();
4158 QVERIFY(object != 0);
4159 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4162 // we haven't registered QList<QPoint> as a sequence type.
4163 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4164 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4165 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4166 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4168 QMetaObject::invokeMethod(object, "performTest");
4170 // QList<QPoint> has not been registered as a sequence type.
4171 QCOMPARE(object->property("pointListLength").toInt(), 0);
4172 QVERIFY(!object->property("pointList").isValid());
4173 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4174 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4175 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4181 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4184 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4185 QDeclarativeComponent component(&engine, qmlFile);
4186 QObject *object = component.create();
4187 QVERIFY(object != 0);
4188 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4191 QMetaObject::invokeMethod(object, "writeSequences");
4192 QCOMPARE(object->property("success").toBool(), true);
4194 QMetaObject::invokeMethod(object, "writeSequenceElements");
4195 QCOMPARE(object->property("success").toBool(), true);
4197 QMetaObject::invokeMethod(object, "writeOtherElements");
4198 QCOMPARE(object->property("success").toBool(), true);
4200 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4201 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4207 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4208 QDeclarativeComponent component(&engine, qmlFile);
4209 QObject *object = component.create();
4210 QVERIFY(object != 0);
4211 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4214 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4215 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4216 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4218 QMetaObject::invokeMethod(object, "performTest");
4220 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4221 QCOMPARE(seq->pointListProperty(), pointList);
4227 void tst_qdeclarativeecmascript::sequenceConversionArray()
4229 // ensure that in JS the returned sequences act just like normal JS Arrays.
4230 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4231 QDeclarativeComponent component(&engine, qmlFile);
4232 QObject *object = component.create();
4233 QVERIFY(object != 0);
4234 QMetaObject::invokeMethod(object, "indexedAccess");
4235 QVERIFY(object->property("success").toBool());
4236 QMetaObject::invokeMethod(object, "arrayOperations");
4237 QVERIFY(object->property("success").toBool());
4238 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4239 QVERIFY(object->property("success").toBool());
4240 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4241 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4245 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4247 // ensure that sequence conversion operations work correctly in a worker thread
4248 // and that serialisation between the main and worker thread succeeds.
4249 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4250 QDeclarativeComponent component(&engine, qmlFile);
4251 QObject *object = component.create();
4252 QVERIFY(object != 0);
4254 QMetaObject::invokeMethod(object, "testIntSequence");
4255 QTRY_VERIFY(object->property("finished").toBool());
4256 QVERIFY(object->property("success").toBool());
4258 QMetaObject::invokeMethod(object, "testQrealSequence");
4259 QTRY_VERIFY(object->property("finished").toBool());
4260 QVERIFY(object->property("success").toBool());
4262 QMetaObject::invokeMethod(object, "testBoolSequence");
4263 QTRY_VERIFY(object->property("finished").toBool());
4264 QVERIFY(object->property("success").toBool());
4266 QMetaObject::invokeMethod(object, "testStringSequence");
4267 QTRY_VERIFY(object->property("finished").toBool());
4268 QVERIFY(object->property("success").toBool());
4270 QMetaObject::invokeMethod(object, "testQStringSequence");
4271 QTRY_VERIFY(object->property("finished").toBool());
4272 QVERIFY(object->property("success").toBool());
4274 QMetaObject::invokeMethod(object, "testUrlSequence");
4275 QTRY_VERIFY(object->property("finished").toBool());
4276 QVERIFY(object->property("success").toBool());
4278 QMetaObject::invokeMethod(object, "testVariantSequence");
4279 QTRY_VERIFY(object->property("finished").toBool());
4280 QVERIFY(object->property("success").toBool());
4285 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4288 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4289 QDeclarativeComponent component(&engine, qmlFile);
4290 QObject *object = component.create();
4291 QVERIFY(object != 0);
4292 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4293 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4294 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4295 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4296 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4301 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4302 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4303 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4304 QDeclarativeComponent component(&engine, qmlFile);
4305 QObject *object = component.create();
4306 QVERIFY(object != 0);
4311 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4313 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4314 QDeclarativeComponent component(&engine, qmlFile);
4315 QObject *object = component.create();
4316 QVERIFY(object != 0);
4317 QMetaObject::invokeMethod(object, "testCopySequences");
4318 QCOMPARE(object->property("success").toBool(), true);
4319 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4320 QCOMPARE(object->property("success").toBool(), true);
4321 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4322 QCOMPARE(object->property("success").toBool(), true);
4326 void tst_qdeclarativeecmascript::assignSequenceTypes()
4328 // test binding array to sequence type property
4330 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.1.qml"));
4331 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4332 QVERIFY(object != 0);
4333 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4334 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4335 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4336 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4337 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4338 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4342 // test binding literal to sequence type property
4344 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.2.qml"));
4345 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4346 QVERIFY(object != 0);
4347 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4348 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4349 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4350 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4351 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4352 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4356 // test binding single value to sequence type property
4358 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.3.qml"));
4359 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4360 QVERIFY(object != 0);
4361 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4362 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4363 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4364 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4368 // test assigning array to sequence type property in js function
4370 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.4.qml"));
4371 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4372 QVERIFY(object != 0);
4373 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4374 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4375 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4376 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4377 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4378 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4382 // test assigning literal to sequence type property in js function
4384 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.5.qml"));
4385 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4386 QVERIFY(object != 0);
4387 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4388 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4389 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4390 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4391 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4392 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4396 // test assigning single value to sequence type property in js function
4398 QDeclarativeComponent component(&engine, TEST_FILE("assignSequenceTypes.6.qml"));
4399 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4400 QVERIFY(object != 0);
4401 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4402 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4403 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4404 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(TEST_FILE("example.html"))));
4409 // Test that assigning a null object works
4410 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4411 void tst_qdeclarativeecmascript::nullObjectBinding()
4413 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4415 QObject *object = component.create();
4416 QVERIFY(object != 0);
4418 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4423 // Test that bindings don't evaluate once the engine has been destroyed
4424 void tst_qdeclarativeecmascript::deletedEngine()
4426 QDeclarativeEngine *engine = new QDeclarativeEngine;
4427 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4429 QObject *object = component.create();
4430 QVERIFY(object != 0);
4432 QCOMPARE(object->property("a").toInt(), 39);
4433 object->setProperty("b", QVariant(9));
4434 QCOMPARE(object->property("a").toInt(), 117);
4438 QCOMPARE(object->property("a").toInt(), 117);
4439 object->setProperty("b", QVariant(10));
4440 QCOMPARE(object->property("a").toInt(), 117);
4445 // Test the crashing part of QTBUG-9705
4446 void tst_qdeclarativeecmascript::libraryScriptAssert()
4448 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4450 QObject *object = component.create();
4451 QVERIFY(object != 0);
4456 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4458 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4460 QObject *object = component.create();
4461 QVERIFY(object != 0);
4463 QCOMPARE(object->property("test1").toInt(), 10);
4464 QCOMPARE(object->property("test2").toInt(), 11);
4466 object->setProperty("runTest", true);
4468 QCOMPARE(object->property("test1"), QVariant());
4469 QCOMPARE(object->property("test2"), QVariant());
4475 void tst_qdeclarativeecmascript::qtbug_9792()
4477 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4479 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4481 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4482 QVERIFY(object != 0);
4484 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4485 object->basicSignal();
4489 transientErrorsMsgCount = 0;
4490 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4492 object->basicSignal();
4494 qInstallMsgHandler(old);
4496 QCOMPARE(transientErrorsMsgCount, 0);
4501 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4502 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4504 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4506 QObject *o = component.create();
4509 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4510 QVERIFY(nested != 0);
4512 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4515 nested = qvariant_cast<QObject *>(o->property("object"));
4516 QVERIFY(nested == 0);
4518 // If the bug is present, the next line will crash
4522 // Test that we shut down without stupid warnings
4523 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4526 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4528 QObject *o = component.create();
4530 transientErrorsMsgCount = 0;
4531 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4535 qInstallMsgHandler(old);
4537 QCOMPARE(transientErrorsMsgCount, 0);
4542 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4544 QObject *o = component.create();
4546 transientErrorsMsgCount = 0;
4547 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4551 qInstallMsgHandler(old);
4553 QCOMPARE(transientErrorsMsgCount, 0);
4557 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4560 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4562 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4565 QVERIFY(o->objectProperty() != 0);
4567 o->setProperty("runTest", true);
4569 QVERIFY(o->objectProperty() == 0);
4575 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4577 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4580 QVERIFY(o->objectProperty() == 0);
4586 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4588 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4590 QString url = component.url().toString();
4591 QString warning = url + ":4: Unable to assign a function to a property.";
4592 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4594 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4597 QVERIFY(!o->property("a").isValid());
4602 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4604 QFETCH(QString, triggerProperty);
4606 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4607 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4609 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4611 QVERIFY(!o->property("a").isValid());
4613 o->setProperty("aNumber", QVariant(5));
4614 o->setProperty(triggerProperty.toUtf8().constData(), true);
4615 QCOMPARE(o->property("a"), QVariant(50));
4617 o->setProperty("aNumber", QVariant(10));
4618 QCOMPARE(o->property("a"), QVariant(100));
4623 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4625 QTest::addColumn<QString>("triggerProperty");
4627 QTest::newRow("assign to property") << "assignToProperty";
4628 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4630 QTest::newRow("assign to value type") << "assignToValueType";
4632 QTest::newRow("use 'this'") << "assignWithThis";
4633 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4636 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4638 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4639 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4641 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4643 QVERIFY(!o->property("a").isValid());
4645 o->setProperty("assignFuncWithoutReturn", true);
4646 QVERIFY(!o->property("a").isValid());
4648 QString url = component.url().toString();
4649 QString warning = url + ":67: Unable to assign QString to int";
4650 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4651 o->setProperty("assignWrongType", true);
4653 warning = url + ":71: Unable to assign QString to int";
4654 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4655 o->setProperty("assignWrongTypeToValueType", true);
4660 void tst_qdeclarativeecmascript::eval()
4662 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4664 QObject *o = component.create();
4667 QCOMPARE(o->property("test1").toBool(), true);
4668 QCOMPARE(o->property("test2").toBool(), true);
4669 QCOMPARE(o->property("test3").toBool(), true);
4670 QCOMPARE(o->property("test4").toBool(), true);
4671 QCOMPARE(o->property("test5").toBool(), true);
4676 void tst_qdeclarativeecmascript::function()
4678 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4680 QObject *o = component.create();
4683 QCOMPARE(o->property("test1").toBool(), true);
4684 QCOMPARE(o->property("test2").toBool(), true);
4685 QCOMPARE(o->property("test3").toBool(), true);
4690 // Test the "Qt.include" method
4691 void tst_qdeclarativeecmascript::include()
4693 // Non-library relative include
4695 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4696 QObject *o = component.create();
4699 QCOMPARE(o->property("test0").toInt(), 99);
4700 QCOMPARE(o->property("test1").toBool(), true);
4701 QCOMPARE(o->property("test2").toBool(), true);
4702 QCOMPARE(o->property("test2_1").toBool(), true);
4703 QCOMPARE(o->property("test3").toBool(), true);
4704 QCOMPARE(o->property("test3_1").toBool(), true);
4709 // Library relative include
4711 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4712 QObject *o = component.create();
4715 QCOMPARE(o->property("test0").toInt(), 99);
4716 QCOMPARE(o->property("test1").toBool(), true);
4717 QCOMPARE(o->property("test2").toBool(), true);
4718 QCOMPARE(o->property("test2_1").toBool(), true);
4719 QCOMPARE(o->property("test3").toBool(), true);
4720 QCOMPARE(o->property("test3_1").toBool(), true);
4727 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4728 QObject *o = component.create();
4731 QCOMPARE(o->property("test1").toBool(), true);
4732 QCOMPARE(o->property("test2").toBool(), true);
4733 QCOMPARE(o->property("test3").toBool(), true);
4734 QCOMPARE(o->property("test4").toBool(), true);
4735 QCOMPARE(o->property("test5").toBool(), true);
4736 QCOMPARE(o->property("test6").toBool(), true);
4741 // Including file with ".pragma library"
4743 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4744 QObject *o = component.create();
4746 QCOMPARE(o->property("test1").toInt(), 100);
4753 TestHTTPServer server(8111);
4754 QVERIFY(server.isValid());
4755 server.serveDirectory(TESTDATA(""));
4757 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4758 QObject *o = component.create();
4761 QTRY_VERIFY(o->property("done").toBool() == true);
4762 QTRY_VERIFY(o->property("done2").toBool() == true);
4764 QCOMPARE(o->property("test1").toBool(), true);
4765 QCOMPARE(o->property("test2").toBool(), true);
4766 QCOMPARE(o->property("test3").toBool(), true);
4767 QCOMPARE(o->property("test4").toBool(), true);
4768 QCOMPARE(o->property("test5").toBool(), true);
4770 QCOMPARE(o->property("test6").toBool(), true);
4771 QCOMPARE(o->property("test7").toBool(), true);
4772 QCOMPARE(o->property("test8").toBool(), true);
4773 QCOMPARE(o->property("test9").toBool(), true);
4774 QCOMPARE(o->property("test10").toBool(), true);
4781 TestHTTPServer server(8111);
4782 QVERIFY(server.isValid());
4783 server.serveDirectory(TESTDATA(""));
4785 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4786 QObject *o = component.create();
4789 QTRY_VERIFY(o->property("done").toBool() == true);
4791 QCOMPARE(o->property("test1").toBool(), true);
4792 QCOMPARE(o->property("test2").toBool(), true);
4793 QCOMPARE(o->property("test3").toBool(), true);
4799 void tst_qdeclarativeecmascript::signalHandlers()
4801 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4802 QObject *o = component.create();
4805 QVERIFY(o->property("count").toInt() == 0);
4806 QMetaObject::invokeMethod(o, "testSignalCall");
4807 QCOMPARE(o->property("count").toInt(), 1);
4809 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4810 QCOMPARE(o->property("count").toInt(), 1);
4811 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4813 QVERIFY(o->property("funcCount").toInt() == 0);
4814 QMetaObject::invokeMethod(o, "testSignalConnection");
4815 QCOMPARE(o->property("funcCount").toInt(), 1);
4817 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4818 QCOMPARE(o->property("funcCount").toInt(), 2);
4820 QMetaObject::invokeMethod(o, "testSignalDefined");
4821 QCOMPARE(o->property("definedResult").toBool(), true);
4823 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4824 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4829 void tst_qdeclarativeecmascript::qtbug_10696()
4831 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4832 QObject *o = component.create();
4837 void tst_qdeclarativeecmascript::qtbug_11606()
4839 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4840 QObject *o = component.create();
4842 QCOMPARE(o->property("test").toBool(), true);
4846 void tst_qdeclarativeecmascript::qtbug_11600()
4848 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4849 QObject *o = component.create();
4851 QCOMPARE(o->property("test").toBool(), true);
4855 void tst_qdeclarativeecmascript::qtbug_21864()
4857 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21864.qml"));
4858 QObject *o = component.create();
4860 QCOMPARE(o->property("test").toBool(), true);
4864 // Reading and writing non-scriptable properties should fail
4865 void tst_qdeclarativeecmascript::nonscriptable()
4867 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4868 QObject *o = component.create();
4870 QCOMPARE(o->property("readOk").toBool(), true);
4871 QCOMPARE(o->property("writeOk").toBool(), true);
4875 // deleteLater() should not be callable from QML
4876 void tst_qdeclarativeecmascript::deleteLater()
4878 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4879 QObject *o = component.create();
4881 QCOMPARE(o->property("test").toBool(), true);
4885 void tst_qdeclarativeecmascript::in()
4887 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4888 QObject *o = component.create();
4890 QCOMPARE(o->property("test1").toBool(), true);
4891 QCOMPARE(o->property("test2").toBool(), true);
4895 void tst_qdeclarativeecmascript::typeOf()
4897 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4899 // These warnings should not happen once QTBUG-21864 is fixed
4900 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
4901 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
4903 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
4904 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
4906 QObject *o = component.create();
4909 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4910 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4911 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4912 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4913 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4914 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4915 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4916 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4917 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4918 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4923 void tst_qdeclarativeecmascript::sharedAttachedObject()
4925 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4926 QObject *o = component.create();
4928 QCOMPARE(o->property("test1").toBool(), true);
4929 QCOMPARE(o->property("test2").toBool(), true);
4934 void tst_qdeclarativeecmascript::objectName()
4936 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4937 QObject *o = component.create();
4940 QCOMPARE(o->property("test1").toString(), QString("hello"));
4941 QCOMPARE(o->property("test2").toString(), QString("ell"));
4943 o->setObjectName("world");
4945 QCOMPARE(o->property("test1").toString(), QString("world"));
4946 QCOMPARE(o->property("test2").toString(), QString("orl"));
4951 void tst_qdeclarativeecmascript::writeRemovesBinding()
4953 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4954 QObject *o = component.create();
4957 QCOMPARE(o->property("test").toBool(), true);
4962 // Test bindings assigned to alias properties actually assign to the alias' target
4963 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4965 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4966 QObject *o = component.create();
4969 QCOMPARE(o->property("test").toBool(), true);
4974 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4975 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4978 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4979 QObject *o = component.create();
4982 QCOMPARE(o->property("test").toBool(), true);
4988 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4989 QObject *o = component.create();
4992 QCOMPARE(o->property("test").toBool(), true);
4998 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4999 QObject *o = component.create();
5002 QCOMPARE(o->property("test").toBool(), true);
5008 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5009 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5012 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
5013 QObject *o = component.create();
5016 QCOMPARE(o->property("test").toBool(), true);
5022 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
5023 QObject *o = component.create();
5026 QCOMPARE(o->property("test").toBool(), true);
5032 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
5033 QObject *o = component.create();
5036 QCOMPARE(o->property("test").toBool(), true);
5042 // Allow an alais to a composite element
5044 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5046 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
5048 QObject *object = component.create();
5049 QVERIFY(object != 0);
5054 void tst_qdeclarativeecmascript::qtbug_20344()
5056 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
5058 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5059 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5061 QObject *object = component.create();
5062 QVERIFY(object != 0);
5067 void tst_qdeclarativeecmascript::revisionErrors()
5070 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
5071 QString url = component.url().toString();
5073 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5074 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5075 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5077 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5078 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5079 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5080 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5081 QVERIFY(object != 0);
5085 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
5086 QString url = component.url().toString();
5088 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5089 // method2, prop2 from MyRevisionedClass not available
5090 // method4, prop4 from MyRevisionedSubclass not available
5091 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5092 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5093 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5094 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5095 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5097 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5098 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5099 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5100 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5101 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5102 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5103 QVERIFY(object != 0);
5107 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5108 QString url = component.url().toString();
5110 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5111 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5112 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5113 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5114 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5115 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5116 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5117 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5118 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5119 QVERIFY(object != 0);
5124 void tst_qdeclarativeecmascript::revision()
5127 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5128 QString url = component.url().toString();
5130 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5131 QVERIFY(object != 0);
5135 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5136 QString url = component.url().toString();
5138 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5139 QVERIFY(object != 0);
5143 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5144 QString url = component.url().toString();
5146 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5147 QVERIFY(object != 0);
5150 // Test that non-root classes can resolve revisioned methods
5152 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5154 QObject *object = component.create();
5155 QVERIFY(object != 0);
5156 QCOMPARE(object->property("test").toReal(), 11.);
5161 void tst_qdeclarativeecmascript::realToInt()
5163 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5164 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5165 QVERIFY(object != 0);
5167 QMetaObject::invokeMethod(object, "test1");
5168 QCOMPARE(object->value(), int(4));
5169 QMetaObject::invokeMethod(object, "test2");
5170 QCOMPARE(object->value(), int(8));
5172 void tst_qdeclarativeecmascript::dynamicString()
5174 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5175 QObject *object = component.create();
5176 QVERIFY(object != 0);
5177 QCOMPARE(object->property("stringProperty").toString(),
5178 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5181 void tst_qdeclarativeecmascript::automaticSemicolon()
5183 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5184 QObject *object = component.create();
5185 QVERIFY(object != 0);
5188 void tst_qdeclarativeecmascript::unaryExpression()
5190 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5191 QObject *object = component.create();
5192 QVERIFY(object != 0);
5195 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5196 void tst_qdeclarativeecmascript::doubleEvaluate()
5198 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5199 QObject *object = component.create();
5200 QVERIFY(object != 0);
5201 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5203 QCOMPARE(wc->count(), 1);
5205 wc->setProperty("x", 9);
5207 QCOMPARE(wc->count(), 2);
5212 static QStringList messages;
5213 static void captureMsgHandler(QtMsgType, const char *msg)
5215 messages.append(QLatin1String(msg));
5218 void tst_qdeclarativeecmascript::nonNotifyable()
5220 QV4Compiler::enableV4(false);
5221 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5222 QV4Compiler::enableV4(true);
5224 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5226 QObject *object = component.create();
5227 qInstallMsgHandler(old);
5229 QVERIFY(object != 0);
5231 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5232 component.url().toString() +
5233 QLatin1String(":5 depends on non-NOTIFYable properties:");
5234 QString expected2 = QLatin1String(" ") +
5235 QLatin1String(object->metaObject()->className()) +
5236 QLatin1String("::value");
5238 QCOMPARE(messages.length(), 2);
5239 QCOMPARE(messages.at(0), expected1);
5240 QCOMPARE(messages.at(1), expected2);
5245 void tst_qdeclarativeecmascript::forInLoop()
5247 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5248 QObject *object = component.create();
5249 QVERIFY(object != 0);
5251 QMetaObject::invokeMethod(object, "listProperty");
5253 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5254 QCOMPARE(r.size(), 3);
5255 QCOMPARE(r[0],QLatin1String("0=obj1"));
5256 QCOMPARE(r[1],QLatin1String("1=obj2"));
5257 QCOMPARE(r[2],QLatin1String("2=obj3"));
5259 //TODO: should test for in loop for other objects (such as QObjects) as well.
5264 // An object the binding depends on is deleted while the binding is still running
5265 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5267 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5268 QObject *object = component.create();
5269 QVERIFY(object != 0);
5273 void tst_qdeclarativeecmascript::qtbug_22679()
5276 object.setStringProperty(QLatin1String("Please work correctly"));
5277 engine.rootContext()->setContextProperty("contextProp", &object);
5279 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5280 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5281 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5283 QObject *o = component.create();
5285 QCOMPARE(warningsSpy.count(), 0);
5289 void tst_qdeclarativeecmascript::qtbug_22843_data()
5291 QTest::addColumn<bool>("library");
5293 QTest::newRow("without .pragma library") << false;
5294 QTest::newRow("with .pragma library") << true;
5297 void tst_qdeclarativeecmascript::qtbug_22843()
5299 QFETCH(bool, library);
5301 QString fileName("qtbug_22843");
5303 fileName += QLatin1String(".library");
5304 fileName += QLatin1String(".qml");
5306 QDeclarativeComponent component(&engine, TEST_FILE(fileName));
5307 QString url = component.url().toString();
5308 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5309 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5311 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5312 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5313 for (int x = 0; x < 3; ++x) {
5314 warningsSpy.clear();
5315 // For libraries, only the first import attempt should produce a
5316 // SyntaxError warning; subsequent component creation should not
5317 // attempt to reload the script.
5318 bool expectSyntaxError = !library || (x == 0);
5319 if (expectSyntaxError)
5320 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5321 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5322 QObject *object = component.create();
5323 QVERIFY(object != 0);
5324 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5330 void tst_qdeclarativeecmascript::switchStatement()
5333 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.1.qml"));
5334 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5335 QVERIFY(object != 0);
5337 // `object->value()' is the number of executed statements
5339 object->setStringProperty("A");
5340 QCOMPARE(object->value(), 5);
5342 object->setStringProperty("S");
5343 QCOMPARE(object->value(), 3);
5345 object->setStringProperty("D");
5346 QCOMPARE(object->value(), 3);
5348 object->setStringProperty("F");
5349 QCOMPARE(object->value(), 4);
5351 object->setStringProperty("something else");
5352 QCOMPARE(object->value(), 1);
5356 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.2.qml"));
5357 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5358 QVERIFY(object != 0);
5360 // `object->value()' is the number of executed statements
5362 object->setStringProperty("A");
5363 QCOMPARE(object->value(), 5);
5365 object->setStringProperty("S");
5366 QCOMPARE(object->value(), 3);
5368 object->setStringProperty("D");
5369 QCOMPARE(object->value(), 3);
5371 object->setStringProperty("F");
5372 QCOMPARE(object->value(), 3);
5374 object->setStringProperty("something else");
5375 QCOMPARE(object->value(), 4);
5379 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.3.qml"));
5380 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5381 QVERIFY(object != 0);
5383 // `object->value()' is the number of executed statements
5385 object->setStringProperty("A");
5386 QCOMPARE(object->value(), 5);
5388 object->setStringProperty("S");
5389 QCOMPARE(object->value(), 3);
5391 object->setStringProperty("D");
5392 QCOMPARE(object->value(), 3);
5394 object->setStringProperty("F");
5395 QCOMPARE(object->value(), 3);
5397 object->setStringProperty("something else");
5398 QCOMPARE(object->value(), 6);
5402 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.4.qml"));
5404 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5405 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5407 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5408 QVERIFY(object != 0);
5410 // `object->value()' is the number of executed statements
5412 object->setStringProperty("A");
5413 QCOMPARE(object->value(), 5);
5415 object->setStringProperty("S");
5416 QCOMPARE(object->value(), 3);
5418 object->setStringProperty("D");
5419 QCOMPARE(object->value(), 3);
5421 object->setStringProperty("F");
5422 QCOMPARE(object->value(), 3);
5424 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5426 object->setStringProperty("something else");
5430 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.5.qml"));
5431 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5432 QVERIFY(object != 0);
5434 // `object->value()' is the number of executed statements
5436 object->setStringProperty("A");
5437 QCOMPARE(object->value(), 1);
5439 object->setStringProperty("S");
5440 QCOMPARE(object->value(), 1);
5442 object->setStringProperty("D");
5443 QCOMPARE(object->value(), 1);
5445 object->setStringProperty("F");
5446 QCOMPARE(object->value(), 1);
5448 object->setStringProperty("something else");
5449 QCOMPARE(object->value(), 1);
5453 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.6.qml"));
5454 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5455 QVERIFY(object != 0);
5457 // `object->value()' is the number of executed statements
5459 object->setStringProperty("A");
5460 QCOMPARE(object->value(), 123);
5462 object->setStringProperty("S");
5463 QCOMPARE(object->value(), 123);
5465 object->setStringProperty("D");
5466 QCOMPARE(object->value(), 321);
5468 object->setStringProperty("F");
5469 QCOMPARE(object->value(), 321);
5471 object->setStringProperty("something else");
5472 QCOMPARE(object->value(), 0);
5476 void tst_qdeclarativeecmascript::withStatement()
5479 QDeclarativeComponent component(&engine, TEST_FILE("withStatement.1.qml"));
5480 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5481 QVERIFY(object != 0);
5483 QCOMPARE(object->value(), 123);
5487 void tst_qdeclarativeecmascript::tryStatement()
5490 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.1.qml"));
5491 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5492 QVERIFY(object != 0);
5494 QCOMPARE(object->value(), 123);
5498 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.2.qml"));
5499 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5500 QVERIFY(object != 0);
5502 QCOMPARE(object->value(), 321);
5506 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.3.qml"));
5507 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5508 QVERIFY(object != 0);
5510 QCOMPARE(object->value(), 1);
5514 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.4.qml"));
5515 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5516 QVERIFY(object != 0);
5518 QCOMPARE(object->value(), 1);
5522 QTEST_MAIN(tst_qdeclarativeecmascript)
5524 #include "tst_qdeclarativeecmascript.moc"