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();
183 void dynamicCreationCrash();
184 void dynamicCreationOwnership();
186 void nullObjectBinding();
187 void deletedEngine();
188 void libraryScriptAssert();
189 void variantsAssignedUndefined();
191 void qtcreatorbug_1289();
192 void noSpuriousWarningsAtShutdown();
193 void canAssignNullToQObject();
194 void functionAssignment_fromBinding();
195 void functionAssignment_fromJS();
196 void functionAssignment_fromJS_data();
197 void functionAssignmentfromJS_invalid();
203 void nonscriptable();
207 void sharedAttachedObject();
209 void writeRemovesBinding();
210 void aliasBindingsAssignCorrectly();
211 void aliasBindingsOverrideTarget();
212 void aliasWritesOverrideBindings();
213 void aliasToCompositeElement();
215 void dynamicString();
217 void signalHandlers();
218 void doubleEvaluate();
220 void nonNotifyable();
221 void deleteWhileBindingRunning();
222 void callQtInvokables();
223 void invokableObjectArg();
224 void invokableObjectRet();
226 void revisionErrors();
229 void automaticSemicolon();
230 void unaryExpression();
233 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
234 QDeclarativeEngine engine;
237 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
239 void tst_qdeclarativeecmascript::assignBasicTypes()
242 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
243 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
244 QVERIFY(object != 0);
245 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
246 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
247 QCOMPARE(object->stringProperty(), QString("Hello World!"));
248 QCOMPARE(object->uintProperty(), uint(10));
249 QCOMPARE(object->intProperty(), -19);
250 QCOMPARE((float)object->realProperty(), float(23.2));
251 QCOMPARE((float)object->doubleProperty(), float(-19.75));
252 QCOMPARE((float)object->floatProperty(), float(8.5));
253 QCOMPARE(object->colorProperty(), QColor("red"));
254 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
255 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
256 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
257 QCOMPARE(object->pointProperty(), QPoint(99,13));
258 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
259 QCOMPARE(object->sizeProperty(), QSize(99, 13));
260 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
261 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
262 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
263 QCOMPARE(object->boolProperty(), true);
264 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
265 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
266 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
270 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
271 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
272 QVERIFY(object != 0);
273 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
274 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
275 QCOMPARE(object->stringProperty(), QString("Hello World!"));
276 QCOMPARE(object->uintProperty(), uint(10));
277 QCOMPARE(object->intProperty(), -19);
278 QCOMPARE((float)object->realProperty(), float(23.2));
279 QCOMPARE((float)object->doubleProperty(), float(-19.75));
280 QCOMPARE((float)object->floatProperty(), float(8.5));
281 QCOMPARE(object->colorProperty(), QColor("red"));
282 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
283 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
284 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
285 QCOMPARE(object->pointProperty(), QPoint(99,13));
286 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
287 QCOMPARE(object->sizeProperty(), QSize(99, 13));
288 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
289 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
290 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
291 QCOMPARE(object->boolProperty(), true);
292 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
293 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
294 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
299 void tst_qdeclarativeecmascript::idShortcutInvalidates()
302 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
303 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
304 QVERIFY(object != 0);
305 QVERIFY(object->objectProperty() != 0);
306 delete object->objectProperty();
307 QVERIFY(object->objectProperty() == 0);
312 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.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 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
325 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
326 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
327 QVERIFY(object != 0);
328 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
332 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
333 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
334 QVERIFY(object != 0);
335 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
340 void tst_qdeclarativeecmascript::signalAssignment()
343 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
344 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
345 QVERIFY(object != 0);
346 QCOMPARE(object->string(), QString());
347 emit object->basicSignal();
348 QCOMPARE(object->string(), QString("pass"));
353 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
354 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
355 QVERIFY(object != 0);
356 QCOMPARE(object->string(), QString());
357 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
358 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
363 void tst_qdeclarativeecmascript::methods()
366 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
367 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
368 QVERIFY(object != 0);
369 QCOMPARE(object->methodCalled(), false);
370 QCOMPARE(object->methodIntCalled(), false);
371 emit object->basicSignal();
372 QCOMPARE(object->methodCalled(), true);
373 QCOMPARE(object->methodIntCalled(), false);
378 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
379 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
380 QVERIFY(object != 0);
381 QCOMPARE(object->methodCalled(), false);
382 QCOMPARE(object->methodIntCalled(), false);
383 emit object->basicSignal();
384 QCOMPARE(object->methodCalled(), false);
385 QCOMPARE(object->methodIntCalled(), true);
390 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
391 QObject *object = component.create();
392 QVERIFY(object != 0);
393 QCOMPARE(object->property("test").toInt(), 19);
398 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
399 QObject *object = component.create();
400 QVERIFY(object != 0);
401 QCOMPARE(object->property("test").toInt(), 19);
402 QCOMPARE(object->property("test2").toInt(), 17);
403 QCOMPARE(object->property("test3").toInt(), 16);
408 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
409 QObject *object = component.create();
410 QVERIFY(object != 0);
411 QCOMPARE(object->property("test").toInt(), 9);
416 void tst_qdeclarativeecmascript::bindingLoop()
418 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
419 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
420 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
421 QObject *object = component.create();
422 QVERIFY(object != 0);
426 void tst_qdeclarativeecmascript::basicExpressions_data()
428 QTest::addColumn<QString>("expression");
429 QTest::addColumn<QVariant>("result");
430 QTest::addColumn<bool>("nest");
432 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
433 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
434 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
435 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
436 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
437 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
438 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
439 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
440 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
441 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
442 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
443 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
444 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
445 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
446 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
447 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
448 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
449 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
450 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
453 void tst_qdeclarativeecmascript::basicExpressions()
455 QFETCH(QString, expression);
456 QFETCH(QVariant, result);
462 MyDefaultObject1 default1;
463 MyDefaultObject3 default3;
464 object1.setStringProperty("Object1");
465 object2.setStringProperty("Object2");
466 object3.setStringProperty("Object3");
468 QDeclarativeContext context(engine.rootContext());
469 QDeclarativeContext nestedContext(&context);
471 context.setContextObject(&default1);
472 context.setContextProperty("a", QVariant(1944));
473 context.setContextProperty("b", QVariant("Milk"));
474 context.setContextProperty("object", &object1);
475 context.setContextProperty("objectOverride", &object2);
476 nestedContext.setContextObject(&default3);
477 nestedContext.setContextProperty("b", QVariant("Cow"));
478 nestedContext.setContextProperty("objectOverride", &object3);
479 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
481 MyExpression expr(nest?&nestedContext:&context, expression);
482 QCOMPARE(expr.evaluate(), result);
485 void tst_qdeclarativeecmascript::arrayExpressions()
491 QDeclarativeContext context(engine.rootContext());
492 context.setContextProperty("a", &obj1);
493 context.setContextProperty("b", &obj2);
494 context.setContextProperty("c", &obj3);
496 MyExpression expr(&context, "[a, b, c, 10]");
497 QVariant result = expr.evaluate();
498 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
499 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
500 QCOMPARE(list.count(), 4);
501 QCOMPARE(list.at(0), &obj1);
502 QCOMPARE(list.at(1), &obj2);
503 QCOMPARE(list.at(2), &obj3);
504 QCOMPARE(list.at(3), (QObject *)0);
507 // Tests that modifying a context property will reevaluate expressions
508 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
510 QDeclarativeContext context(engine.rootContext());
513 MyQmlObject *object3 = new MyQmlObject;
515 object1.setStringProperty("Hello");
516 object2.setStringProperty("World");
518 context.setContextProperty("testProp", QVariant(1));
519 context.setContextProperty("testObj", &object1);
520 context.setContextProperty("testObj2", object3);
523 MyExpression expr(&context, "testProp + 1");
524 QCOMPARE(expr.changed, false);
525 QCOMPARE(expr.evaluate(), QVariant(2));
527 context.setContextProperty("testProp", QVariant(2));
528 QCOMPARE(expr.changed, true);
529 QCOMPARE(expr.evaluate(), QVariant(3));
533 MyExpression expr(&context, "testProp + testProp + testProp");
534 QCOMPARE(expr.changed, false);
535 QCOMPARE(expr.evaluate(), QVariant(6));
537 context.setContextProperty("testProp", QVariant(4));
538 QCOMPARE(expr.changed, true);
539 QCOMPARE(expr.evaluate(), QVariant(12));
543 MyExpression expr(&context, "testObj.stringProperty");
544 QCOMPARE(expr.changed, false);
545 QCOMPARE(expr.evaluate(), QVariant("Hello"));
547 context.setContextProperty("testObj", &object2);
548 QCOMPARE(expr.changed, true);
549 QCOMPARE(expr.evaluate(), QVariant("World"));
553 MyExpression expr(&context, "testObj.stringProperty /**/");
554 QCOMPARE(expr.changed, false);
555 QCOMPARE(expr.evaluate(), QVariant("World"));
557 context.setContextProperty("testObj", &object1);
558 QCOMPARE(expr.changed, true);
559 QCOMPARE(expr.evaluate(), QVariant("Hello"));
563 MyExpression expr(&context, "testObj2");
564 QCOMPARE(expr.changed, false);
565 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
571 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
573 QDeclarativeContext context(engine.rootContext());
577 context.setContextProperty("testObj", &object1);
579 object1.setStringProperty(QLatin1String("Hello"));
580 object2.setStringProperty(QLatin1String("Dog"));
581 object3.setStringProperty(QLatin1String("Cat"));
584 MyExpression expr(&context, "testObj.stringProperty");
585 QCOMPARE(expr.changed, false);
586 QCOMPARE(expr.evaluate(), QVariant("Hello"));
588 object1.setStringProperty(QLatin1String("World"));
589 QCOMPARE(expr.changed, true);
590 QCOMPARE(expr.evaluate(), QVariant("World"));
594 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
595 QCOMPARE(expr.changed, false);
596 QCOMPARE(expr.evaluate(), QVariant());
598 object1.setObjectProperty(&object2);
599 QCOMPARE(expr.changed, true);
600 expr.changed = false;
601 QCOMPARE(expr.evaluate(), QVariant("Dog"));
603 object1.setObjectProperty(&object3);
604 QCOMPARE(expr.changed, true);
605 expr.changed = false;
606 QCOMPARE(expr.evaluate(), QVariant("Cat"));
608 object1.setObjectProperty(0);
609 QCOMPARE(expr.changed, true);
610 expr.changed = false;
611 QCOMPARE(expr.evaluate(), QVariant());
613 object1.setObjectProperty(&object3);
614 QCOMPARE(expr.changed, true);
615 expr.changed = false;
616 QCOMPARE(expr.evaluate(), QVariant("Cat"));
618 object3.setStringProperty("Donkey");
619 QCOMPARE(expr.changed, true);
620 expr.changed = false;
621 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
625 void tst_qdeclarativeecmascript::deferredProperties()
627 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
628 MyDeferredObject *object =
629 qobject_cast<MyDeferredObject *>(component.create());
630 QVERIFY(object != 0);
631 QCOMPARE(object->value(), 0);
632 QVERIFY(object->objectProperty() == 0);
633 QVERIFY(object->objectProperty2() != 0);
634 qmlExecuteDeferred(object);
635 QCOMPARE(object->value(), 10);
636 QVERIFY(object->objectProperty() != 0);
637 MyQmlObject *qmlObject =
638 qobject_cast<MyQmlObject *>(object->objectProperty());
639 QVERIFY(qmlObject != 0);
640 QCOMPARE(qmlObject->value(), 10);
641 object->setValue(19);
642 QCOMPARE(qmlObject->value(), 19);
647 // Check errors on deferred properties are correctly emitted
648 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
650 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
651 MyDeferredObject *object =
652 qobject_cast<MyDeferredObject *>(component.create());
653 QVERIFY(object != 0);
654 QCOMPARE(object->value(), 0);
655 QVERIFY(object->objectProperty() == 0);
656 QVERIFY(object->objectProperty2() == 0);
658 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
659 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
661 qmlExecuteDeferred(object);
666 void tst_qdeclarativeecmascript::extensionObjects()
668 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
669 MyExtendedObject *object =
670 qobject_cast<MyExtendedObject *>(component.create());
671 QVERIFY(object != 0);
672 QCOMPARE(object->baseProperty(), 13);
673 QCOMPARE(object->coreProperty(), 9);
674 object->setProperty("extendedProperty", QVariant(11));
675 object->setProperty("baseExtendedProperty", QVariant(92));
676 QCOMPARE(object->coreProperty(), 11);
677 QCOMPARE(object->baseProperty(), 92);
679 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
681 QCOMPARE(nested->baseProperty(), 13);
682 QCOMPARE(nested->coreProperty(), 9);
683 nested->setProperty("extendedProperty", QVariant(11));
684 nested->setProperty("baseExtendedProperty", QVariant(92));
685 QCOMPARE(nested->coreProperty(), 11);
686 QCOMPARE(nested->baseProperty(), 92);
691 void tst_qdeclarativeecmascript::overrideExtensionProperties()
693 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
694 OverrideDefaultPropertyObject *object =
695 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
696 QVERIFY(object != 0);
697 QVERIFY(object->secondProperty() != 0);
698 QVERIFY(object->firstProperty() == 0);
703 void tst_qdeclarativeecmascript::attachedProperties()
706 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
707 QObject *object = component.create();
708 QVERIFY(object != 0);
709 QCOMPARE(object->property("a").toInt(), 19);
710 QCOMPARE(object->property("b").toInt(), 19);
711 QCOMPARE(object->property("c").toInt(), 19);
712 QCOMPARE(object->property("d").toInt(), 19);
717 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
718 QObject *object = component.create();
719 QVERIFY(object != 0);
720 QCOMPARE(object->property("a").toInt(), 26);
721 QCOMPARE(object->property("b").toInt(), 26);
722 QCOMPARE(object->property("c").toInt(), 26);
723 QCOMPARE(object->property("d").toInt(), 26);
729 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
730 QObject *object = component.create();
731 QVERIFY(object != 0);
733 QMetaObject::invokeMethod(object, "writeValue2");
735 MyQmlAttachedObject *attached =
736 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
737 QVERIFY(attached != 0);
739 QCOMPARE(attached->value2(), 9);
744 void tst_qdeclarativeecmascript::enums()
748 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
749 QObject *object = component.create();
750 QVERIFY(object != 0);
752 QCOMPARE(object->property("a").toInt(), 0);
753 QCOMPARE(object->property("b").toInt(), 1);
754 QCOMPARE(object->property("c").toInt(), 2);
755 QCOMPARE(object->property("d").toInt(), 3);
756 QCOMPARE(object->property("e").toInt(), 0);
757 QCOMPARE(object->property("f").toInt(), 1);
758 QCOMPARE(object->property("g").toInt(), 2);
759 QCOMPARE(object->property("h").toInt(), 3);
760 QCOMPARE(object->property("i").toInt(), 19);
761 QCOMPARE(object->property("j").toInt(), 19);
765 // Non-existent enums
767 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
769 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
770 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
771 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
772 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
774 QObject *object = component.create();
775 QVERIFY(object != 0);
776 QCOMPARE(object->property("a").toInt(), 0);
777 QCOMPARE(object->property("b").toInt(), 0);
783 void tst_qdeclarativeecmascript::valueTypeFunctions()
785 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
786 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
788 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
789 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
795 Tests that writing a constant to a property with a binding on it disables the
798 void tst_qdeclarativeecmascript::constantsOverrideBindings()
802 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
803 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
804 QVERIFY(object != 0);
806 QCOMPARE(object->property("c2").toInt(), 0);
807 object->setProperty("c1", QVariant(9));
808 QCOMPARE(object->property("c2").toInt(), 9);
810 emit object->basicSignal();
812 QCOMPARE(object->property("c2").toInt(), 13);
813 object->setProperty("c1", QVariant(8));
814 QCOMPARE(object->property("c2").toInt(), 13);
819 // During construction
821 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
822 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
823 QVERIFY(object != 0);
825 QCOMPARE(object->property("c1").toInt(), 0);
826 QCOMPARE(object->property("c2").toInt(), 10);
827 object->setProperty("c1", QVariant(9));
828 QCOMPARE(object->property("c1").toInt(), 9);
829 QCOMPARE(object->property("c2").toInt(), 10);
837 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
838 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
839 QVERIFY(object != 0);
841 QCOMPARE(object->property("c2").toInt(), 0);
842 object->setProperty("c1", QVariant(9));
843 QCOMPARE(object->property("c2").toInt(), 9);
845 object->setProperty("c2", QVariant(13));
846 QCOMPARE(object->property("c2").toInt(), 13);
847 object->setProperty("c1", QVariant(7));
848 QCOMPARE(object->property("c1").toInt(), 7);
849 QCOMPARE(object->property("c2").toInt(), 13);
857 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
858 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
859 QVERIFY(object != 0);
861 QCOMPARE(object->property("c1").toInt(), 0);
862 QCOMPARE(object->property("c3").toInt(), 10);
863 object->setProperty("c1", QVariant(9));
864 QCOMPARE(object->property("c1").toInt(), 9);
865 QCOMPARE(object->property("c3").toInt(), 10);
872 Tests that assigning a binding to a property that already has a binding causes
873 the original binding to be disabled.
875 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
877 QDeclarativeComponent component(&engine,
878 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
879 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
880 QVERIFY(object != 0);
882 QCOMPARE(object->property("c1").toInt(), 0);
883 QCOMPARE(object->property("c2").toInt(), 0);
884 QCOMPARE(object->property("c3").toInt(), 0);
886 object->setProperty("c1", QVariant(9));
887 QCOMPARE(object->property("c1").toInt(), 9);
888 QCOMPARE(object->property("c2").toInt(), 0);
889 QCOMPARE(object->property("c3").toInt(), 0);
891 object->setProperty("c3", QVariant(8));
892 QCOMPARE(object->property("c1").toInt(), 9);
893 QCOMPARE(object->property("c2").toInt(), 8);
894 QCOMPARE(object->property("c3").toInt(), 8);
900 Access a non-existent attached object.
902 Tests for a regression where this used to crash.
904 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
906 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
908 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
909 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
911 QObject *object = component.create();
912 QVERIFY(object != 0);
917 void tst_qdeclarativeecmascript::scope()
920 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
921 QObject *object = component.create();
922 QVERIFY(object != 0);
924 QCOMPARE(object->property("test1").toInt(), 1);
925 QCOMPARE(object->property("test2").toInt(), 2);
926 QCOMPARE(object->property("test3").toString(), QString("1Test"));
927 QCOMPARE(object->property("test4").toString(), QString("2Test"));
928 QCOMPARE(object->property("test5").toInt(), 1);
929 QCOMPARE(object->property("test6").toInt(), 1);
930 QCOMPARE(object->property("test7").toInt(), 2);
931 QCOMPARE(object->property("test8").toInt(), 2);
932 QCOMPARE(object->property("test9").toInt(), 1);
933 QCOMPARE(object->property("test10").toInt(), 3);
939 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
940 QObject *object = component.create();
941 QVERIFY(object != 0);
943 QCOMPARE(object->property("test1").toInt(), 19);
944 QCOMPARE(object->property("test2").toInt(), 19);
945 QCOMPARE(object->property("test3").toInt(), 14);
946 QCOMPARE(object->property("test4").toInt(), 14);
947 QCOMPARE(object->property("test5").toInt(), 24);
948 QCOMPARE(object->property("test6").toInt(), 24);
954 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
955 QObject *object = component.create();
956 QVERIFY(object != 0);
958 QCOMPARE(object->property("test1").toBool(), true);
959 QCOMPARE(object->property("test2").toBool(), true);
960 QCOMPARE(object->property("test3").toBool(), true);
965 // Signal argument scope
967 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
968 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
969 QVERIFY(object != 0);
971 QCOMPARE(object->property("test").toInt(), 0);
972 QCOMPARE(object->property("test2").toString(), QString());
974 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
976 QCOMPARE(object->property("test").toInt(), 13);
977 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
983 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
984 QObject *object = component.create();
985 QVERIFY(object != 0);
987 QCOMPARE(object->property("test1").toBool(), true);
988 QCOMPARE(object->property("test2").toBool(), true);
994 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
995 QObject *object = component.create();
996 QVERIFY(object != 0);
998 QCOMPARE(object->property("test").toBool(), true);
1004 // In 4.7, non-library javascript files that had no imports shared the imports of their
1005 // importing context
1006 void tst_qdeclarativeecmascript::importScope()
1008 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1009 QObject *o = component.create();
1012 QCOMPARE(o->property("test").toInt(), 240);
1018 Tests that "any" type passes through a synthesized signal parameter. This
1019 is essentially a test of QDeclarativeMetaType::copy()
1021 void tst_qdeclarativeecmascript::signalParameterTypes()
1023 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1024 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1025 QVERIFY(object != 0);
1027 emit object->basicSignal();
1029 QCOMPARE(object->property("intProperty").toInt(), 10);
1030 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1031 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1032 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1033 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1034 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1040 Test that two JS objects for the same QObject compare as equal.
1042 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1044 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1045 QObject *object = component.create();
1046 QVERIFY(object != 0);
1048 QCOMPARE(object->property("test1").toBool(), true);
1049 QCOMPARE(object->property("test2").toBool(), true);
1050 QCOMPARE(object->property("test3").toBool(), true);
1051 QCOMPARE(object->property("test4").toBool(), true);
1052 QCOMPARE(object->property("test5").toBool(), true);
1058 Confirm bindings and alias properties can coexist.
1060 Tests for a regression where the binding would not reevaluate.
1062 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1064 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1065 QObject *object = component.create();
1066 QVERIFY(object != 0);
1068 QCOMPARE(object->property("c2").toInt(), 3);
1069 QCOMPARE(object->property("c3").toInt(), 3);
1071 object->setProperty("c2", QVariant(19));
1073 QCOMPARE(object->property("c2").toInt(), 19);
1074 QCOMPARE(object->property("c3").toInt(), 19);
1080 Ensure that we can write undefined value to an alias property,
1081 and that the aliased property is reset correctly if possible.
1083 void tst_qdeclarativeecmascript::aliasPropertyReset()
1085 QObject *object = 0;
1087 // test that a manual write (of undefined) to a resettable aliased property succeeds
1088 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1089 object = c1.create();
1090 QVERIFY(object != 0);
1091 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1092 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1093 QMetaObject::invokeMethod(object, "resetAliased");
1094 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1095 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1098 // test that a manual write (of undefined) to a resettable alias property succeeds
1099 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1100 object = c2.create();
1101 QVERIFY(object != 0);
1102 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1103 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1104 QMetaObject::invokeMethod(object, "resetAlias");
1105 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1106 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1109 // test that an alias to a bound property works correctly
1110 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1111 object = c3.create();
1112 QVERIFY(object != 0);
1113 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1114 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1115 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1116 QMetaObject::invokeMethod(object, "resetAlias");
1117 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1118 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1119 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1122 // test that a manual write (of undefined) to a resettable alias property
1123 // whose aliased property's object has been deleted, does not crash.
1124 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1125 object = c4.create();
1126 QVERIFY(object != 0);
1127 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1128 QObject *loader = object->findChild<QObject*>("loader");
1129 QVERIFY(loader != 0);
1131 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1132 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1133 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1134 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1135 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1138 // test that binding an alias property to an undefined value works correctly
1139 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1140 object = c5.create();
1141 QVERIFY(object != 0);
1142 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1145 // test that a manual write (of undefined) to a non-resettable property fails properly
1146 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1147 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1148 QDeclarativeComponent e1(&engine, url);
1149 object = e1.create();
1150 QVERIFY(object != 0);
1151 QCOMPARE(object->property("intAlias").value<int>(), 12);
1152 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1153 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1154 QMetaObject::invokeMethod(object, "resetAlias");
1155 QCOMPARE(object->property("intAlias").value<int>(), 12);
1156 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1160 void tst_qdeclarativeecmascript::dynamicCreation_data()
1162 QTest::addColumn<QString>("method");
1163 QTest::addColumn<QString>("createdName");
1165 QTest::newRow("One") << "createOne" << "objectOne";
1166 QTest::newRow("Two") << "createTwo" << "objectTwo";
1167 QTest::newRow("Three") << "createThree" << "objectThree";
1171 Test using createQmlObject to dynamically generate an item
1172 Also using createComponent is tested.
1174 void tst_qdeclarativeecmascript::dynamicCreation()
1176 QFETCH(QString, method);
1177 QFETCH(QString, createdName);
1179 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1180 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1181 QVERIFY(object != 0);
1183 QMetaObject::invokeMethod(object, method.toUtf8());
1184 QObject *created = object->objectProperty();
1186 QCOMPARE(created->objectName(), createdName);
1192 Tests the destroy function
1194 void tst_qdeclarativeecmascript::dynamicDestruction()
1197 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1198 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1199 QVERIFY(object != 0);
1200 QDeclarativeGuard<QObject> createdQmlObject = 0;
1202 QMetaObject::invokeMethod(object, "create");
1203 createdQmlObject = object->objectProperty();
1204 QVERIFY(createdQmlObject);
1205 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1207 QMetaObject::invokeMethod(object, "killOther");
1208 QVERIFY(createdQmlObject);
1209 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1210 QVERIFY(createdQmlObject);
1211 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1212 if (createdQmlObject) {
1214 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1217 QVERIFY(!createdQmlObject);
1219 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1220 QMetaObject::invokeMethod(object, "killMe");
1223 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1228 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1229 QObject *o = component.create();
1232 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1234 QMetaObject::invokeMethod(o, "create");
1236 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1238 QMetaObject::invokeMethod(o, "destroy");
1240 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1242 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1249 tests that id.toString() works
1251 void tst_qdeclarativeecmascript::objectToString()
1253 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1254 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1255 QVERIFY(object != 0);
1256 QMetaObject::invokeMethod(object, "testToString");
1257 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1258 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1264 tests that id.hasOwnProperty() works
1266 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1268 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1269 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1270 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1271 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1273 QDeclarativeComponent component(&engine, url);
1274 QObject *object = component.create();
1275 QVERIFY(object != 0);
1277 // test QObjects in QML
1278 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1279 QVERIFY(object->property("result").value<bool>() == true);
1280 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1281 QVERIFY(object->property("result").value<bool>() == false);
1283 // now test other types in QML
1284 QObject *child = object->findChild<QObject*>("typeObj");
1285 QVERIFY(child != 0);
1286 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1287 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1288 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1289 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1290 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1291 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1292 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1293 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1294 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1295 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1296 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1297 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1299 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1300 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1301 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1302 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1303 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1304 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1305 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1306 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1307 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1313 Tests bindings that indirectly cause their own deletion work.
1315 This test is best run under valgrind to ensure no invalid memory access occur.
1317 void tst_qdeclarativeecmascript::selfDeletingBinding()
1320 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1321 QObject *object = component.create();
1322 QVERIFY(object != 0);
1323 object->setProperty("triggerDelete", true);
1328 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1329 QObject *object = component.create();
1330 QVERIFY(object != 0);
1331 object->setProperty("triggerDelete", true);
1337 Test that extended object properties can be accessed.
1339 This test a regression where this used to crash. The issue was specificially
1340 for extended objects that did not include a synthesized meta object (so non-root
1341 and no synthesiszed properties).
1343 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1345 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1346 QObject *object = component.create();
1347 QVERIFY(object != 0);
1352 Test file/lineNumbers for binding/Script errors.
1354 void tst_qdeclarativeecmascript::scriptErrors()
1356 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1357 QString url = component.url().toString();
1359 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1360 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1361 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1362 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1363 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1364 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1365 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1366 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1368 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1369 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1370 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1371 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1372 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1373 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1374 QVERIFY(object != 0);
1376 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1377 emit object->basicSignal();
1379 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1380 emit object->anotherBasicSignal();
1382 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1383 emit object->thirdBasicSignal();
1389 Test file/lineNumbers for inline functions.
1391 void tst_qdeclarativeecmascript::functionErrors()
1393 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1394 QString url = component.url().toString();
1396 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1398 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1400 QObject *object = component.create();
1401 QVERIFY(object != 0);
1404 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1405 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1406 url = componentTwo.url().toString();
1407 object = componentTwo.create();
1408 QVERIFY(object != 0);
1410 QString srpname = object->property("srp_name").toString();
1412 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1413 QLatin1String(" is not a function");
1414 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1415 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1420 Test various errors that can occur when assigning a property from script
1422 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1424 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1426 QString url = component.url().toString();
1428 QObject *object = component.create();
1429 QVERIFY(object != 0);
1431 QCOMPARE(object->property("test1").toBool(), true);
1432 QCOMPARE(object->property("test2").toBool(), true);
1438 Test bindings still work when the reeval is triggered from within
1441 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1443 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1444 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1445 QVERIFY(object != 0);
1447 QCOMPARE(object->property("base").toReal(), 50.);
1448 QCOMPARE(object->property("test1").toReal(), 50.);
1449 QCOMPARE(object->property("test2").toReal(), 50.);
1451 object->basicSignal();
1453 QCOMPARE(object->property("base").toReal(), 200.);
1454 QCOMPARE(object->property("test1").toReal(), 200.);
1455 QCOMPARE(object->property("test2").toReal(), 200.);
1457 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1459 QCOMPARE(object->property("base").toReal(), 400.);
1460 QCOMPARE(object->property("test1").toReal(), 400.);
1461 QCOMPARE(object->property("test2").toReal(), 400.);
1467 Test that list properties can be iterated from ECMAScript
1469 void tst_qdeclarativeecmascript::listProperties()
1471 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1472 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1473 QVERIFY(object != 0);
1475 QCOMPARE(object->property("test1").toInt(), 21);
1476 QCOMPARE(object->property("test2").toInt(), 2);
1477 QCOMPARE(object->property("test3").toBool(), true);
1478 QCOMPARE(object->property("test4").toBool(), true);
1483 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1485 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1486 QString url = component.url().toString();
1488 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1490 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1491 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1492 QVERIFY(object != 0);
1494 QCOMPARE(object->property("test").toBool(), false);
1496 MyQmlObject object2;
1497 MyQmlObject object3;
1498 object2.setObjectProperty(&object3);
1499 object->setObjectProperty(&object2);
1501 QCOMPARE(object->property("test").toBool(), true);
1506 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1508 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1509 QString url = component.url().toString();
1511 QString warning = component.url().toString() + ":6: Error: JS exception";
1513 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1514 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1515 QVERIFY(object != 0);
1519 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1521 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1522 QString url = component.url().toString();
1524 QString warning = component.url().toString() + ":5: Error: JS exception";
1526 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1527 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1528 QVERIFY(object != 0);
1532 static int transientErrorsMsgCount = 0;
1533 static void transientErrorsMsgHandler(QtMsgType, const char *)
1535 ++transientErrorsMsgCount;
1538 // Check that transient binding errors are not displayed
1539 void tst_qdeclarativeecmascript::transientErrors()
1542 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1544 transientErrorsMsgCount = 0;
1545 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1547 QObject *object = component.create();
1548 QVERIFY(object != 0);
1550 qInstallMsgHandler(old);
1552 QCOMPARE(transientErrorsMsgCount, 0);
1557 // One binding erroring multiple times, but then resolving
1559 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1561 transientErrorsMsgCount = 0;
1562 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1564 QObject *object = component.create();
1565 QVERIFY(object != 0);
1567 qInstallMsgHandler(old);
1569 QCOMPARE(transientErrorsMsgCount, 0);
1575 // Check that errors during shutdown are minimized
1576 void tst_qdeclarativeecmascript::shutdownErrors()
1578 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1579 QObject *object = component.create();
1580 QVERIFY(object != 0);
1582 transientErrorsMsgCount = 0;
1583 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1587 qInstallMsgHandler(old);
1588 QCOMPARE(transientErrorsMsgCount, 0);
1591 void tst_qdeclarativeecmascript::compositePropertyType()
1593 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1594 QString messageFormat = QString(QLatin1String("hello world (%1:%2)")).arg(TEST_FILE("compositePropertyType.qml").toString()).arg(7);
1595 QTest::ignoreMessage(QtDebugMsg, qPrintable(messageFormat));
1596 QObject *object = qobject_cast<QObject *>(component.create());
1601 void tst_qdeclarativeecmascript::jsObject()
1603 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1604 QObject *object = component.create();
1605 QVERIFY(object != 0);
1607 QCOMPARE(object->property("test").toInt(), 92);
1612 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1615 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1616 QObject *object = component.create();
1617 QVERIFY(object != 0);
1619 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1621 object->setProperty("setUndefined", true);
1623 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1625 object->setProperty("setUndefined", false);
1627 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1632 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1633 QObject *object = component.create();
1634 QVERIFY(object != 0);
1636 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1638 QMetaObject::invokeMethod(object, "doReset");
1640 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1647 void tst_qdeclarativeecmascript::bug1()
1649 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1650 QObject *object = component.create();
1651 QVERIFY(object != 0);
1653 QCOMPARE(object->property("test").toInt(), 14);
1655 object->setProperty("a", 11);
1657 QCOMPARE(object->property("test").toInt(), 3);
1659 object->setProperty("b", true);
1661 QCOMPARE(object->property("test").toInt(), 9);
1666 void tst_qdeclarativeecmascript::bug2()
1668 QDeclarativeComponent component(&engine);
1669 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1671 QObject *object = component.create();
1672 QVERIFY(object != 0);
1677 // Don't crash in createObject when the component has errors.
1678 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1680 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1681 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1682 QVERIFY(object != 0);
1684 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1685 QMetaObject::invokeMethod(object, "dontCrash");
1686 QObject *created = object->objectProperty();
1687 QVERIFY(created == 0);
1692 // ownership transferred to JS, ensure that GC runs the dtor
1693 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1696 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1698 // allow the engine to go out of scope too.
1700 QDeclarativeEngine dcoEngine;
1701 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1702 QObject *object = component.create();
1703 QVERIFY(object != 0);
1704 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1705 QVERIFY(mdcdo != 0);
1706 mdcdo->setDtorCount(&dtorCount);
1708 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1709 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1711 // we do this once manually, but it should be done automatically
1712 // when the engine goes out of scope (since it should gc in dtor)
1713 QMetaObject::invokeMethod(object, "performGc");
1716 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1722 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1723 QCOMPARE(dtorCount, expectedDtorCount);
1727 void tst_qdeclarativeecmascript::regExpBug()
1729 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1730 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1731 QVERIFY(object != 0);
1732 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1736 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1738 QString functionSource = QLatin1String("(function(object) { return ") +
1739 QLatin1String(source) + QLatin1String(" })");
1741 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1744 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1745 if (function.IsEmpty())
1747 v8::Handle<v8::Value> args[] = { o };
1748 function->Call(engine->global(), 1, args);
1749 return tc.HasCaught();
1752 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1753 const char *source, v8::Handle<v8::Value> result)
1755 QString functionSource = QLatin1String("(function(object) { return ") +
1756 QLatin1String(source) + QLatin1String(" })");
1758 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1761 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1762 if (function.IsEmpty())
1764 v8::Handle<v8::Value> args[] = { o };
1766 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1771 return value->StrictEquals(result);
1774 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1777 QString functionSource = QLatin1String("(function(object) { return ") +
1778 QLatin1String(source) + QLatin1String(" })");
1780 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1782 return v8::Handle<v8::Value>();
1783 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1784 if (function.IsEmpty())
1785 return v8::Handle<v8::Value>();
1786 v8::Handle<v8::Value> args[] = { o };
1788 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1791 return v8::Handle<v8::Value>();
1795 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1796 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1797 #define EVALUATE(source) evaluate(engine, object, source)
1799 void tst_qdeclarativeecmascript::callQtInvokables()
1801 MyInvokableObject o;
1803 QDeclarativeEngine qmlengine;
1804 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1806 QV8Engine *engine = ep->v8engine();
1808 v8::HandleScope handle_scope;
1809 v8::Context::Scope scope(engine->context());
1811 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1813 // Non-existent methods
1815 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1816 QCOMPARE(o.error(), false);
1817 QCOMPARE(o.invoked(), -1);
1818 QCOMPARE(o.actuals().count(), 0);
1821 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1822 QCOMPARE(o.error(), false);
1823 QCOMPARE(o.invoked(), -1);
1824 QCOMPARE(o.actuals().count(), 0);
1826 // Insufficient arguments
1828 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1829 QCOMPARE(o.error(), false);
1830 QCOMPARE(o.invoked(), -1);
1831 QCOMPARE(o.actuals().count(), 0);
1834 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1835 QCOMPARE(o.error(), false);
1836 QCOMPARE(o.invoked(), -1);
1837 QCOMPARE(o.actuals().count(), 0);
1839 // Excessive arguments
1841 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1842 QCOMPARE(o.error(), false);
1843 QCOMPARE(o.invoked(), 8);
1844 QCOMPARE(o.actuals().count(), 1);
1845 QCOMPARE(o.actuals().at(0), QVariant(10));
1848 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1849 QCOMPARE(o.error(), false);
1850 QCOMPARE(o.invoked(), 9);
1851 QCOMPARE(o.actuals().count(), 2);
1852 QCOMPARE(o.actuals().at(0), QVariant(10));
1853 QCOMPARE(o.actuals().at(1), QVariant(11));
1855 // Test return types
1857 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1858 QCOMPARE(o.error(), false);
1859 QCOMPARE(o.invoked(), 0);
1860 QCOMPARE(o.actuals().count(), 0);
1863 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1864 QCOMPARE(o.error(), false);
1865 QCOMPARE(o.invoked(), 1);
1866 QCOMPARE(o.actuals().count(), 0);
1869 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1870 QCOMPARE(o.error(), false);
1871 QCOMPARE(o.invoked(), 2);
1872 QCOMPARE(o.actuals().count(), 0);
1876 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1877 QVERIFY(!ret.IsEmpty());
1878 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1879 QCOMPARE(o.error(), false);
1880 QCOMPARE(o.invoked(), 3);
1881 QCOMPARE(o.actuals().count(), 0);
1886 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1887 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1888 QCOMPARE(o.error(), false);
1889 QCOMPARE(o.invoked(), 4);
1890 QCOMPARE(o.actuals().count(), 0);
1894 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1895 QCOMPARE(o.error(), false);
1896 QCOMPARE(o.invoked(), 5);
1897 QCOMPARE(o.actuals().count(), 0);
1901 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1902 QVERIFY(ret->IsString());
1903 QCOMPARE(engine->toString(ret), QString("Hello world"));
1904 QCOMPARE(o.error(), false);
1905 QCOMPARE(o.invoked(), 6);
1906 QCOMPARE(o.actuals().count(), 0);
1910 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1911 QCOMPARE(o.error(), false);
1912 QCOMPARE(o.invoked(), 7);
1913 QCOMPARE(o.actuals().count(), 0);
1917 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1918 QCOMPARE(o.error(), false);
1919 QCOMPARE(o.invoked(), 8);
1920 QCOMPARE(o.actuals().count(), 1);
1921 QCOMPARE(o.actuals().at(0), QVariant(94));
1924 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1925 QCOMPARE(o.error(), false);
1926 QCOMPARE(o.invoked(), 8);
1927 QCOMPARE(o.actuals().count(), 1);
1928 QCOMPARE(o.actuals().at(0), QVariant(94));
1931 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1932 QCOMPARE(o.error(), false);
1933 QCOMPARE(o.invoked(), 8);
1934 QCOMPARE(o.actuals().count(), 1);
1935 QCOMPARE(o.actuals().at(0), QVariant(0));
1938 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1939 QCOMPARE(o.error(), false);
1940 QCOMPARE(o.invoked(), 8);
1941 QCOMPARE(o.actuals().count(), 1);
1942 QCOMPARE(o.actuals().at(0), QVariant(0));
1945 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1946 QCOMPARE(o.error(), false);
1947 QCOMPARE(o.invoked(), 8);
1948 QCOMPARE(o.actuals().count(), 1);
1949 QCOMPARE(o.actuals().at(0), QVariant(0));
1952 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1953 QCOMPARE(o.error(), false);
1954 QCOMPARE(o.invoked(), 8);
1955 QCOMPARE(o.actuals().count(), 1);
1956 QCOMPARE(o.actuals().at(0), QVariant(0));
1959 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1960 QCOMPARE(o.error(), false);
1961 QCOMPARE(o.invoked(), 9);
1962 QCOMPARE(o.actuals().count(), 2);
1963 QCOMPARE(o.actuals().at(0), QVariant(122));
1964 QCOMPARE(o.actuals().at(1), QVariant(9));
1967 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1968 QCOMPARE(o.error(), false);
1969 QCOMPARE(o.invoked(), 10);
1970 QCOMPARE(o.actuals().count(), 1);
1971 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1974 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1975 QCOMPARE(o.error(), false);
1976 QCOMPARE(o.invoked(), 10);
1977 QCOMPARE(o.actuals().count(), 1);
1978 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1981 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1982 QCOMPARE(o.error(), false);
1983 QCOMPARE(o.invoked(), 10);
1984 QCOMPARE(o.actuals().count(), 1);
1985 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1988 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1989 QCOMPARE(o.error(), false);
1990 QCOMPARE(o.invoked(), 10);
1991 QCOMPARE(o.actuals().count(), 1);
1992 QCOMPARE(o.actuals().at(0), QVariant(0));
1995 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1996 QCOMPARE(o.error(), false);
1997 QCOMPARE(o.invoked(), 10);
1998 QCOMPARE(o.actuals().count(), 1);
1999 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2002 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2003 QCOMPARE(o.error(), false);
2004 QCOMPARE(o.invoked(), 10);
2005 QCOMPARE(o.actuals().count(), 1);
2006 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2009 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2010 QCOMPARE(o.error(), false);
2011 QCOMPARE(o.invoked(), 11);
2012 QCOMPARE(o.actuals().count(), 1);
2013 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2016 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2017 QCOMPARE(o.error(), false);
2018 QCOMPARE(o.invoked(), 11);
2019 QCOMPARE(o.actuals().count(), 1);
2020 QCOMPARE(o.actuals().at(0), QVariant("19"));
2024 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2025 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2026 QCOMPARE(o.error(), false);
2027 QCOMPARE(o.invoked(), 11);
2028 QCOMPARE(o.actuals().count(), 1);
2029 QCOMPARE(o.actuals().at(0), QVariant(expected));
2033 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2034 QCOMPARE(o.error(), false);
2035 QCOMPARE(o.invoked(), 11);
2036 QCOMPARE(o.actuals().count(), 1);
2037 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2040 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2041 QCOMPARE(o.error(), false);
2042 QCOMPARE(o.invoked(), 11);
2043 QCOMPARE(o.actuals().count(), 1);
2044 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2047 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2048 QCOMPARE(o.error(), false);
2049 QCOMPARE(o.invoked(), 12);
2050 QCOMPARE(o.actuals().count(), 1);
2051 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2054 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2055 QCOMPARE(o.error(), false);
2056 QCOMPARE(o.invoked(), 12);
2057 QCOMPARE(o.actuals().count(), 1);
2058 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2061 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2062 QCOMPARE(o.error(), false);
2063 QCOMPARE(o.invoked(), 12);
2064 QCOMPARE(o.actuals().count(), 1);
2065 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2068 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2069 QCOMPARE(o.error(), false);
2070 QCOMPARE(o.invoked(), 12);
2071 QCOMPARE(o.actuals().count(), 1);
2072 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2075 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2076 QCOMPARE(o.error(), false);
2077 QCOMPARE(o.invoked(), 12);
2078 QCOMPARE(o.actuals().count(), 1);
2079 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2082 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2083 QCOMPARE(o.error(), false);
2084 QCOMPARE(o.invoked(), 12);
2085 QCOMPARE(o.actuals().count(), 1);
2086 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2089 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2090 QCOMPARE(o.error(), false);
2091 QCOMPARE(o.invoked(), 13);
2092 QCOMPARE(o.actuals().count(), 1);
2093 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2096 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2097 QCOMPARE(o.error(), false);
2098 QCOMPARE(o.invoked(), 13);
2099 QCOMPARE(o.actuals().count(), 1);
2100 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2103 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2104 QCOMPARE(o.error(), false);
2105 QCOMPARE(o.invoked(), 13);
2106 QCOMPARE(o.actuals().count(), 1);
2107 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2110 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2111 QCOMPARE(o.error(), false);
2112 QCOMPARE(o.invoked(), 13);
2113 QCOMPARE(o.actuals().count(), 1);
2114 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2117 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2118 QCOMPARE(o.error(), false);
2119 QCOMPARE(o.invoked(), 13);
2120 QCOMPARE(o.actuals().count(), 1);
2121 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2124 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2125 QCOMPARE(o.error(), false);
2126 QCOMPARE(o.invoked(), 14);
2127 QCOMPARE(o.actuals().count(), 1);
2128 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2131 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2132 QCOMPARE(o.error(), false);
2133 QCOMPARE(o.invoked(), 14);
2134 QCOMPARE(o.actuals().count(), 1);
2135 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2138 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2139 QCOMPARE(o.error(), false);
2140 QCOMPARE(o.invoked(), 14);
2141 QCOMPARE(o.actuals().count(), 1);
2142 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2145 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2146 QCOMPARE(o.error(), false);
2147 QCOMPARE(o.invoked(), 14);
2148 QCOMPARE(o.actuals().count(), 1);
2149 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2152 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2153 QCOMPARE(o.error(), false);
2154 QCOMPARE(o.invoked(), 15);
2155 QCOMPARE(o.actuals().count(), 2);
2156 QCOMPARE(o.actuals().at(0), QVariant(4));
2157 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2160 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2161 QCOMPARE(o.error(), false);
2162 QCOMPARE(o.invoked(), 15);
2163 QCOMPARE(o.actuals().count(), 2);
2164 QCOMPARE(o.actuals().at(0), QVariant(8));
2165 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2168 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2169 QCOMPARE(o.error(), false);
2170 QCOMPARE(o.invoked(), 15);
2171 QCOMPARE(o.actuals().count(), 2);
2172 QCOMPARE(o.actuals().at(0), QVariant(3));
2173 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2176 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2177 QCOMPARE(o.error(), false);
2178 QCOMPARE(o.invoked(), 15);
2179 QCOMPARE(o.actuals().count(), 2);
2180 QCOMPARE(o.actuals().at(0), QVariant(44));
2181 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2184 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2185 QCOMPARE(o.error(), false);
2186 QCOMPARE(o.invoked(), -1);
2187 QCOMPARE(o.actuals().count(), 0);
2190 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2191 QCOMPARE(o.error(), false);
2192 QCOMPARE(o.invoked(), 16);
2193 QCOMPARE(o.actuals().count(), 1);
2194 QCOMPARE(o.actuals().at(0), QVariant(10));
2197 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2198 QCOMPARE(o.error(), false);
2199 QCOMPARE(o.invoked(), 17);
2200 QCOMPARE(o.actuals().count(), 2);
2201 QCOMPARE(o.actuals().at(0), QVariant(10));
2202 QCOMPARE(o.actuals().at(1), QVariant(11));
2205 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2206 QCOMPARE(o.error(), false);
2207 QCOMPARE(o.invoked(), 18);
2208 QCOMPARE(o.actuals().count(), 1);
2209 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2212 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2213 QCOMPARE(o.error(), false);
2214 QCOMPARE(o.invoked(), 19);
2215 QCOMPARE(o.actuals().count(), 1);
2216 QCOMPARE(o.actuals().at(0), QVariant(9));
2219 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2220 QCOMPARE(o.error(), false);
2221 QCOMPARE(o.invoked(), 20);
2222 QCOMPARE(o.actuals().count(), 2);
2223 QCOMPARE(o.actuals().at(0), QVariant(10));
2224 QCOMPARE(o.actuals().at(1), QVariant(19));
2227 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2228 QCOMPARE(o.error(), false);
2229 QCOMPARE(o.invoked(), 20);
2230 QCOMPARE(o.actuals().count(), 2);
2231 QCOMPARE(o.actuals().at(0), QVariant(10));
2232 QCOMPARE(o.actuals().at(1), QVariant(13));
2235 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2236 QCOMPARE(o.error(), false);
2237 QCOMPARE(o.invoked(), -3);
2238 QCOMPARE(o.actuals().count(), 1);
2239 QCOMPARE(o.actuals().at(0), QVariant(9));
2242 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2243 QCOMPARE(o.error(), false);
2244 QCOMPARE(o.invoked(), 21);
2245 QCOMPARE(o.actuals().count(), 2);
2246 QCOMPARE(o.actuals().at(0), QVariant(9));
2247 QCOMPARE(o.actuals().at(1), QVariant());
2250 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2251 QCOMPARE(o.error(), false);
2252 QCOMPARE(o.invoked(), 21);
2253 QCOMPARE(o.actuals().count(), 2);
2254 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2255 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2258 // QTBUG-13047 (check that you can pass registered object types as args)
2259 void tst_qdeclarativeecmascript::invokableObjectArg()
2261 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2263 QObject *o = component.create();
2265 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2267 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2272 // QTBUG-13047 (check that you can return registered object types from methods)
2273 void tst_qdeclarativeecmascript::invokableObjectRet()
2275 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2277 QObject *o = component.create();
2279 QCOMPARE(o->property("test").toBool(), true);
2284 void tst_qdeclarativeecmascript::listToVariant()
2286 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2288 MyQmlContainer container;
2290 QDeclarativeContext context(engine.rootContext());
2291 context.setContextObject(&container);
2293 QObject *object = component.create(&context);
2294 QVERIFY(object != 0);
2296 QVariant v = object->property("test");
2297 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2298 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2304 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2305 void tst_qdeclarativeecmascript::listAssignment()
2307 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2308 QObject *obj = component.create();
2309 QCOMPARE(obj->property("list1length").toInt(), 2);
2310 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2311 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2312 QCOMPARE(list1.count(&list1), list2.count(&list2));
2313 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2314 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2319 void tst_qdeclarativeecmascript::multiEngineObject()
2322 obj.setStringProperty("Howdy planet");
2324 QDeclarativeEngine e1;
2325 e1.rootContext()->setContextProperty("thing", &obj);
2326 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2328 QDeclarativeEngine e2;
2329 e2.rootContext()->setContextProperty("thing", &obj);
2330 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2332 QObject *o1 = c1.create();
2333 QObject *o2 = c2.create();
2335 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2336 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2342 // Test that references to QObjects are cleanup when the object is destroyed
2343 void tst_qdeclarativeecmascript::deletedObject()
2345 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2347 QObject *object = component.create();
2349 QCOMPARE(object->property("test1").toBool(), true);
2350 QCOMPARE(object->property("test2").toBool(), true);
2351 QCOMPARE(object->property("test3").toBool(), true);
2352 QCOMPARE(object->property("test4").toBool(), true);
2357 void tst_qdeclarativeecmascript::attachedPropertyScope()
2359 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2361 QObject *object = component.create();
2362 QVERIFY(object != 0);
2364 MyQmlAttachedObject *attached =
2365 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2366 QVERIFY(attached != 0);
2368 QCOMPARE(object->property("value2").toInt(), 0);
2370 attached->emitMySignal();
2372 QCOMPARE(object->property("value2").toInt(), 9);
2377 void tst_qdeclarativeecmascript::scriptConnect()
2380 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2382 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2383 QVERIFY(object != 0);
2385 QCOMPARE(object->property("test").toBool(), false);
2386 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2387 QCOMPARE(object->property("test").toBool(), true);
2393 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2395 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2396 QVERIFY(object != 0);
2398 QCOMPARE(object->property("test").toBool(), false);
2399 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2400 QCOMPARE(object->property("test").toBool(), true);
2406 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2408 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2409 QVERIFY(object != 0);
2411 QCOMPARE(object->property("test").toBool(), false);
2412 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2413 QCOMPARE(object->property("test").toBool(), true);
2419 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2421 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2422 QVERIFY(object != 0);
2424 QCOMPARE(object->methodCalled(), false);
2425 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2426 QCOMPARE(object->methodCalled(), true);
2432 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2434 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2435 QVERIFY(object != 0);
2437 QCOMPARE(object->methodCalled(), false);
2438 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2439 QCOMPARE(object->methodCalled(), true);
2445 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2447 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2448 QVERIFY(object != 0);
2450 QCOMPARE(object->property("test").toInt(), 0);
2451 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2452 QCOMPARE(object->property("test").toInt(), 2);
2458 void tst_qdeclarativeecmascript::scriptDisconnect()
2461 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2463 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2464 QVERIFY(object != 0);
2466 QCOMPARE(object->property("test").toInt(), 0);
2467 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2468 QCOMPARE(object->property("test").toInt(), 1);
2469 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2470 QCOMPARE(object->property("test").toInt(), 2);
2471 emit object->basicSignal();
2472 QCOMPARE(object->property("test").toInt(), 2);
2473 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2474 QCOMPARE(object->property("test").toInt(), 2);
2480 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2482 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2483 QVERIFY(object != 0);
2485 QCOMPARE(object->property("test").toInt(), 0);
2486 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2487 QCOMPARE(object->property("test").toInt(), 1);
2488 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2489 QCOMPARE(object->property("test").toInt(), 2);
2490 emit object->basicSignal();
2491 QCOMPARE(object->property("test").toInt(), 2);
2492 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2493 QCOMPARE(object->property("test").toInt(), 2);
2499 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2501 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2502 QVERIFY(object != 0);
2504 QCOMPARE(object->property("test").toInt(), 0);
2505 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2506 QCOMPARE(object->property("test").toInt(), 1);
2507 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2508 QCOMPARE(object->property("test").toInt(), 2);
2509 emit object->basicSignal();
2510 QCOMPARE(object->property("test").toInt(), 2);
2511 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2512 QCOMPARE(object->property("test").toInt(), 3);
2517 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2519 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2520 QVERIFY(object != 0);
2522 QCOMPARE(object->property("test").toInt(), 0);
2523 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2524 QCOMPARE(object->property("test").toInt(), 1);
2525 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2526 QCOMPARE(object->property("test").toInt(), 2);
2527 emit object->basicSignal();
2528 QCOMPARE(object->property("test").toInt(), 2);
2529 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2530 QCOMPARE(object->property("test").toInt(), 3);
2536 class OwnershipObject : public QObject
2540 OwnershipObject() { object = new QObject; }
2542 QPointer<QObject> object;
2545 QObject *getObject() { return object; }
2548 void tst_qdeclarativeecmascript::ownership()
2550 OwnershipObject own;
2551 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2552 context->setContextObject(&own);
2555 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2557 QVERIFY(own.object != 0);
2559 QObject *object = component.create(context);
2561 engine.collectGarbage();
2563 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2565 QVERIFY(own.object == 0);
2570 own.object = new QObject(&own);
2573 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2575 QVERIFY(own.object != 0);
2577 QObject *object = component.create(context);
2579 engine.collectGarbage();
2581 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2583 QVERIFY(own.object != 0);
2591 class CppOwnershipReturnValue : public QObject
2595 CppOwnershipReturnValue() : value(0) {}
2596 ~CppOwnershipReturnValue() { delete value; }
2598 Q_INVOKABLE QObject *create() {
2599 value = new QObject;
2600 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2604 Q_INVOKABLE MyQmlObject *createQmlObject() {
2605 MyQmlObject *rv = new MyQmlObject;
2610 QPointer<QObject> value;
2614 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2615 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2617 CppOwnershipReturnValue source;
2620 QDeclarativeEngine engine;
2621 engine.rootContext()->setContextProperty("source", &source);
2623 QVERIFY(source.value == 0);
2625 QDeclarativeComponent component(&engine);
2626 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2628 QObject *object = component.create();
2630 QVERIFY(object != 0);
2631 QVERIFY(source.value != 0);
2636 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2638 QVERIFY(source.value != 0);
2642 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2644 CppOwnershipReturnValue source;
2647 QDeclarativeEngine engine;
2648 engine.rootContext()->setContextProperty("source", &source);
2650 QVERIFY(source.value == 0);
2652 QDeclarativeComponent component(&engine);
2653 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2655 QObject *object = component.create();
2657 QVERIFY(object != 0);
2658 QVERIFY(source.value != 0);
2663 engine.collectGarbage();
2664 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2666 QVERIFY(source.value == 0);
2669 class QListQObjectMethodsObject : public QObject
2673 QListQObjectMethodsObject() {
2674 m_objects.append(new MyQmlObject());
2675 m_objects.append(new MyQmlObject());
2678 ~QListQObjectMethodsObject() {
2679 qDeleteAll(m_objects);
2683 QList<QObject *> getObjects() { return m_objects; }
2686 QList<QObject *> m_objects;
2689 // Tests that returning a QList<QObject*> from a method works
2690 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2692 QListQObjectMethodsObject obj;
2693 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2694 context->setContextObject(&obj);
2696 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2698 QObject *object = component.create(context);
2700 QCOMPARE(object->property("test").toInt(), 2);
2701 QCOMPARE(object->property("test2").toBool(), true);
2708 void tst_qdeclarativeecmascript::strictlyEquals()
2710 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2712 QObject *object = component.create();
2713 QVERIFY(object != 0);
2715 QCOMPARE(object->property("test1").toBool(), true);
2716 QCOMPARE(object->property("test2").toBool(), true);
2717 QCOMPARE(object->property("test3").toBool(), true);
2718 QCOMPARE(object->property("test4").toBool(), true);
2719 QCOMPARE(object->property("test5").toBool(), true);
2720 QCOMPARE(object->property("test6").toBool(), true);
2721 QCOMPARE(object->property("test7").toBool(), true);
2722 QCOMPARE(object->property("test8").toBool(), true);
2727 void tst_qdeclarativeecmascript::compiled()
2729 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2731 QObject *object = component.create();
2732 QVERIFY(object != 0);
2734 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2735 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2736 QCOMPARE(object->property("test3").toBool(), true);
2737 QCOMPARE(object->property("test4").toBool(), false);
2738 QCOMPARE(object->property("test5").toBool(), false);
2739 QCOMPARE(object->property("test6").toBool(), true);
2741 QCOMPARE(object->property("test7").toInt(), 185);
2742 QCOMPARE(object->property("test8").toInt(), 167);
2743 QCOMPARE(object->property("test9").toBool(), true);
2744 QCOMPARE(object->property("test10").toBool(), false);
2745 QCOMPARE(object->property("test11").toBool(), false);
2746 QCOMPARE(object->property("test12").toBool(), true);
2748 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2749 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2750 QCOMPARE(object->property("test15").toBool(), false);
2751 QCOMPARE(object->property("test16").toBool(), true);
2753 QCOMPARE(object->property("test17").toInt(), 5);
2754 QCOMPARE(object->property("test18").toReal(), qreal(176));
2755 QCOMPARE(object->property("test19").toInt(), 7);
2756 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2757 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2758 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2759 QCOMPARE(object->property("test23").toBool(), true);
2760 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2761 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2766 // Test that numbers assigned in bindings as strings work consistently
2767 void tst_qdeclarativeecmascript::numberAssignment()
2769 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2771 QObject *object = component.create();
2772 QVERIFY(object != 0);
2774 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2775 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2776 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2777 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2778 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2780 QCOMPARE(object->property("test5"), QVariant((int)7));
2781 QCOMPARE(object->property("test6"), QVariant((int)7));
2782 QCOMPARE(object->property("test7"), QVariant((int)6));
2783 QCOMPARE(object->property("test8"), QVariant((int)6));
2785 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2786 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2787 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2788 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2793 void tst_qdeclarativeecmascript::propertySplicing()
2795 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2797 QObject *object = component.create();
2798 QVERIFY(object != 0);
2800 QCOMPARE(object->property("test").toBool(), true);
2806 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2808 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2810 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2811 QVERIFY(object != 0);
2813 MyQmlObject::MyType type;
2814 type.value = 0x8971123;
2815 emit object->signalWithUnknownType(type);
2817 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2819 QCOMPARE(result.value, type.value);
2825 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2827 QTest::addColumn<QString>("expression");
2828 QTest::addColumn<QString>("compare");
2830 QString compareStrict("(function(a, b) { return a === b; })");
2831 QTest::newRow("true") << "true" << compareStrict;
2832 QTest::newRow("undefined") << "undefined" << compareStrict;
2833 QTest::newRow("null") << "null" << compareStrict;
2834 QTest::newRow("123") << "123" << compareStrict;
2835 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2837 QString comparePropertiesStrict(
2839 " if (typeof b != 'object')"
2841 " var props = Object.getOwnPropertyNames(b);"
2842 " for (var i = 0; i < props.length; ++i) {"
2843 " var p = props[i];"
2844 " return arguments.callee(a[p], b[p]);"
2847 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2848 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2851 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2853 QFETCH(QString, expression);
2854 QFETCH(QString, compare);
2856 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2857 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2858 QVERIFY(object != 0);
2860 QJSValue value = engine.evaluate(expression);
2861 QVERIFY(!engine.hasUncaughtException());
2862 object->setProperty("expression", expression);
2863 object->setProperty("compare", compare);
2864 object->setProperty("pass", false);
2866 emit object->signalWithVariant(QVariant::fromValue(value));
2867 QVERIFY(object->property("pass").toBool());
2870 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2872 signalWithJSValueInVariant_data();
2875 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2877 QFETCH(QString, expression);
2878 QFETCH(QString, compare);
2880 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2881 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2882 QVERIFY(object != 0);
2885 QJSValue value = engine2.evaluate(expression);
2886 QVERIFY(!engine2.hasUncaughtException());
2887 object->setProperty("expression", expression);
2888 object->setProperty("compare", compare);
2889 object->setProperty("pass", false);
2891 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2892 emit object->signalWithVariant(QVariant::fromValue(value));
2893 QVERIFY(!object->property("pass").toBool());
2896 void tst_qdeclarativeecmascript::moduleApi_data()
2898 QTest::addColumn<QUrl>("testfile");
2899 QTest::addColumn<QString>("errorMessage");
2900 QTest::addColumn<QStringList>("warningMessages");
2901 QTest::addColumn<QStringList>("readProperties");
2902 QTest::addColumn<QVariantList>("readExpectedValues");
2903 QTest::addColumn<QStringList>("writeProperties");
2904 QTest::addColumn<QVariantList>("writeValues");
2905 QTest::addColumn<QStringList>("readBackProperties");
2906 QTest::addColumn<QVariantList>("readBackExpectedValues");
2908 QTest::newRow("qobject, register + read + method")
2909 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2912 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2913 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2914 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2920 QTest::newRow("script, register + read")
2921 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2924 << (QStringList() << "scriptTest")
2925 << (QVariantList() << 13)
2931 QTest::newRow("qobject, caching + read")
2932 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2935 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2936 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2942 QTest::newRow("script, caching + read")
2943 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2946 << (QStringList() << "scriptTest")
2947 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2953 QTest::newRow("qobject, writing + readonly constraints")
2954 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2956 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2957 << (QStringList() << "readOnlyProperty" << "writableProperty")
2958 << (QVariantList() << 20 << 50)
2959 << (QStringList() << "firstProperty" << "writableProperty")
2960 << (QVariantList() << 30 << 30)
2961 << (QStringList() << "readOnlyProperty" << "writableProperty")
2962 << (QVariantList() << 20 << 30);
2964 QTest::newRow("script, writing + readonly constraints")
2965 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2967 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2968 << (QStringList() << "readBack" << "unchanged")
2969 << (QVariantList() << 13 << 42)
2970 << (QStringList() << "firstProperty" << "secondProperty")
2971 << (QVariantList() << 30 << 30)
2972 << (QStringList() << "readBack" << "unchanged")
2973 << (QVariantList() << 30 << 42);
2975 QTest::newRow("qobject module API enum values in JS")
2976 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2979 << (QStringList() << "enumValue" << "enumMethod")
2980 << (QVariantList() << 42 << 30)
2986 QTest::newRow("qobject, invalid major version fail")
2987 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2988 << QString("QDeclarativeComponent: Component is not ready")
2997 QTest::newRow("qobject, invalid minor version fail")
2998 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2999 << QString("QDeclarativeComponent: Component is not ready")
3009 void tst_qdeclarativeecmascript::moduleApi()
3011 QFETCH(QUrl, testfile);
3012 QFETCH(QString, errorMessage);
3013 QFETCH(QStringList, warningMessages);
3014 QFETCH(QStringList, readProperties);
3015 QFETCH(QVariantList, readExpectedValues);
3016 QFETCH(QStringList, writeProperties);
3017 QFETCH(QVariantList, writeValues);
3018 QFETCH(QStringList, readBackProperties);
3019 QFETCH(QVariantList, readBackExpectedValues);
3021 QDeclarativeComponent component(&engine, testfile);
3023 if (!errorMessage.isEmpty())
3024 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3026 if (warningMessages.size())
3027 foreach (const QString &warning, warningMessages)
3028 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3030 QObject *object = component.create();
3031 if (!errorMessage.isEmpty()) {
3032 QVERIFY(object == 0);
3034 QVERIFY(object != 0);
3035 for (int i = 0; i < readProperties.size(); ++i)
3036 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3037 for (int i = 0; i < writeProperties.size(); ++i)
3038 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3039 for (int i = 0; i < readBackProperties.size(); ++i)
3040 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3045 void tst_qdeclarativeecmascript::importScripts_data()
3047 QTest::addColumn<QUrl>("testfile");
3048 QTest::addColumn<QString>("errorMessage");
3049 QTest::addColumn<QStringList>("warningMessages");
3050 QTest::addColumn<QStringList>("propertyNames");
3051 QTest::addColumn<QVariantList>("propertyValues");
3053 QTest::newRow("basic functionality")
3054 << TEST_FILE("jsimport/testImport.qml")
3057 << (QStringList() << QLatin1String("importedScriptStringValue")
3058 << QLatin1String("importedScriptFunctionValue")
3059 << QLatin1String("importedModuleAttachedPropertyValue")
3060 << QLatin1String("importedModuleEnumValue"))
3061 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3066 QTest::newRow("import scoping")
3067 << TEST_FILE("jsimport/testImportScoping.qml")
3070 << (QStringList() << QLatin1String("componentError"))
3071 << (QVariantList() << QVariant(5));
3073 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3074 << TEST_FILE("jsimportfail/failOne.qml")
3076 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3077 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3078 << (QVariantList() << QVariant(QString()));
3080 QTest::newRow("javascript imports in an import should be private to the import scope")
3081 << TEST_FILE("jsimportfail/failTwo.qml")
3083 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3084 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3085 << (QVariantList() << QVariant(QString()));
3087 QTest::newRow("module imports in an import should be private to the import scope")
3088 << TEST_FILE("jsimportfail/failThree.qml")
3090 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3091 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3092 << (QVariantList() << QVariant(false));
3094 QTest::newRow("typenames in an import should be private to the import scope")
3095 << TEST_FILE("jsimportfail/failFour.qml")
3097 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3098 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3099 << (QVariantList() << QVariant(0));
3101 QTest::newRow("import with imports has it's own activation scope")
3102 << TEST_FILE("jsimportfail/failFive.qml")
3104 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3105 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3106 << (QStringList() << QLatin1String("componentError"))
3107 << (QVariantList() << QVariant(0));
3109 QTest::newRow("import pragma library script")
3110 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3113 << (QStringList() << QLatin1String("testValue"))
3114 << (QVariantList() << QVariant(31));
3116 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3117 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3120 << (QStringList() << QLatin1String("testValue"))
3121 << (QVariantList() << QVariant(0));
3123 QTest::newRow("import pragma library script which has an import")
3124 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3127 << (QStringList() << QLatin1String("testValue"))
3128 << (QVariantList() << QVariant(55));
3130 QTest::newRow("import pragma library script which has a pragma library import")
3131 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3134 << (QStringList() << QLatin1String("testValue"))
3135 << (QVariantList() << QVariant(18));
3138 void tst_qdeclarativeecmascript::importScripts()
3140 QFETCH(QUrl, testfile);
3141 QFETCH(QString, errorMessage);
3142 QFETCH(QStringList, warningMessages);
3143 QFETCH(QStringList, propertyNames);
3144 QFETCH(QVariantList, propertyValues);
3146 QDeclarativeComponent component(&engine, testfile);
3148 if (!errorMessage.isEmpty())
3149 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3151 if (warningMessages.size())
3152 foreach (const QString &warning, warningMessages)
3153 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3155 QObject *object = component.create();
3156 if (!errorMessage.isEmpty()) {
3157 QVERIFY(object == 0);
3159 QVERIFY(object != 0);
3160 for (int i = 0; i < propertyNames.size(); ++i)
3161 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3166 void tst_qdeclarativeecmascript::scarceResources()
3168 QPixmap origPixmap(100, 100);
3169 origPixmap.fill(Qt::blue);
3171 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3172 ScarceResourceObject *eo = 0;
3173 QObject *object = 0;
3175 // in the following three cases, the instance created from the component
3176 // has a property which is a copy of the scarce resource; hence, the
3177 // resource should NOT be detached prior to deletion of the object instance,
3178 // unless the resource is destroyed explicitly.
3179 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3180 object = component.create();
3181 QVERIFY(object != 0);
3182 QVERIFY(object->property("scarceResourceCopy").isValid());
3183 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3184 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3185 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3186 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3189 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3190 object = componentTwo.create();
3191 QVERIFY(object != 0);
3192 QVERIFY(object->property("scarceResourceCopy").isValid());
3193 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3194 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3195 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3196 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3199 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3200 object = componentThree.create();
3201 QVERIFY(object != 0);
3202 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3203 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3204 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3205 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3208 // in the following three cases, no other copy should exist in memory,
3209 // and so it should be detached (unless explicitly preserved).
3210 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3211 object = componentFour.create();
3212 QVERIFY(object != 0);
3213 QVERIFY(object->property("scarceResourceTest").isValid());
3214 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3215 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3216 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3217 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3220 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3221 object = componentFive.create();
3222 QVERIFY(object != 0);
3223 QVERIFY(object->property("scarceResourceTest").isValid());
3224 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3225 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3226 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3227 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3230 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3231 object = componentSix.create();
3232 QVERIFY(object != 0);
3233 QVERIFY(object->property("scarceResourceTest").isValid());
3234 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3235 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3236 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3237 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3240 // test that scarce resources are handled correctly for imports
3241 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3242 object = componentSeven.create();
3243 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3244 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3247 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3248 object = componentEight.create();
3249 QVERIFY(object != 0);
3250 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3251 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3254 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3255 object = componentNine.create();
3256 QVERIFY(object != 0);
3257 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3258 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3259 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3260 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3261 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3262 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3265 // test that scarce resources are handled properly in signal invocation
3266 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3267 object = componentTen.create();
3268 QVERIFY(object != 0);
3269 QObject *srsc = object->findChild<QObject*>("srsc");
3271 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3272 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3273 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3274 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3275 QMetaObject::invokeMethod(srsc, "testSignal");
3276 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3277 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3278 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3279 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3280 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3281 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3282 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3283 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3284 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3285 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3288 // test that scarce resources are handled properly from js functions in qml files
3289 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3290 object = componentEleven.create();
3291 QVERIFY(object != 0);
3292 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3293 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3294 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3295 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3296 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3297 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3298 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3299 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3300 QMetaObject::invokeMethod(object, "releaseScarceResource");
3301 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3302 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3303 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3304 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3307 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3308 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3309 object = componentTwelve.create();
3310 QVERIFY(object != 0);
3311 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3312 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3313 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3314 QString srp_name = object->property("srp_name").toString();
3315 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3316 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3317 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3318 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3319 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3320 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3321 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3325 void tst_qdeclarativeecmascript::propertyChangeSlots()
3327 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3328 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3329 QObject *object = component.create();
3330 QVERIFY(object != 0);
3333 // ensure that invalid property names fail properly.
3334 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3335 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3336 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3337 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3338 object = e1.create();
3339 QVERIFY(object == 0);
3342 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3343 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3344 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3345 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3346 object = e2.create();
3347 QVERIFY(object == 0);
3350 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3351 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3352 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3353 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3354 object = e3.create();
3355 QVERIFY(object == 0);
3358 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3359 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3360 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3361 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3362 object = e4.create();
3363 QVERIFY(object == 0);
3367 void tst_qdeclarativeecmascript::propertyVar_data()
3369 QTest::addColumn<QUrl>("qmlFile");
3372 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3373 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3374 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3375 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3376 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3377 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3378 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3379 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3380 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3383 void tst_qdeclarativeecmascript::propertyVar()
3385 QFETCH(QUrl, qmlFile);
3387 QDeclarativeComponent component(&engine, qmlFile);
3388 QObject *object = component.create();
3389 QVERIFY(object != 0);
3391 QCOMPARE(object->property("test").toBool(), true);
3396 // Tests that we can write QVariant values to var properties from C++
3397 void tst_qdeclarativeecmascript::propertyVarCpp()
3399 QObject *object = 0;
3401 // ensure that writing to and reading from a var property from cpp works as required.
3402 // Literal values stored in var properties can be read and written as QVariants
3403 // of a specific type, whereas object values are read as QVariantMaps.
3404 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3405 object = component.create();
3406 QVERIFY(object != 0);
3407 // assign int to property var that currently has int assigned
3408 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3409 QCOMPARE(object->property("varBound"), QVariant(15));
3410 QCOMPARE(object->property("intBound"), QVariant(15));
3411 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3412 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3413 // assign string to property var that current has bool assigned
3414 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3415 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3416 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3417 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3418 // now enforce behaviour when accessing JavaScript objects from cpp.
3419 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3423 static void gc(QDeclarativeEngine &engine)
3425 engine.collectGarbage();
3426 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3429 void tst_qdeclarativeecmascript::propertyVarOwnership()
3431 // Referenced JS objects are not collected
3433 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3434 QObject *object = component.create();
3435 QVERIFY(object != 0);
3436 QCOMPARE(object->property("test").toBool(), false);
3437 QMetaObject::invokeMethod(object, "runTest");
3438 QCOMPARE(object->property("test").toBool(), true);
3441 // Referenced JS objects are not collected
3443 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3444 QObject *object = component.create();
3445 QVERIFY(object != 0);
3446 QCOMPARE(object->property("test").toBool(), false);
3447 QMetaObject::invokeMethod(object, "runTest");
3448 QCOMPARE(object->property("test").toBool(), true);
3451 // Qt objects are not collected until they've been dereferenced
3453 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3454 QObject *object = component.create();
3455 QVERIFY(object != 0);
3457 QCOMPARE(object->property("test2").toBool(), false);
3458 QCOMPARE(object->property("test2").toBool(), false);
3460 QMetaObject::invokeMethod(object, "runTest");
3461 QCOMPARE(object->property("test1").toBool(), true);
3463 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3464 QVERIFY(!referencedObject.isNull());
3466 QVERIFY(!referencedObject.isNull());
3468 QMetaObject::invokeMethod(object, "runTest2");
3469 QCOMPARE(object->property("test2").toBool(), true);
3471 QVERIFY(referencedObject.isNull());
3475 // Self reference does not prevent Qt object collection
3477 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3478 QObject *object = component.create();
3479 QVERIFY(object != 0);
3481 QCOMPARE(object->property("test").toBool(), true);
3483 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3484 QVERIFY(!referencedObject.isNull());
3486 QVERIFY(!referencedObject.isNull());
3488 QMetaObject::invokeMethod(object, "runTest");
3490 QVERIFY(referencedObject.isNull());
3496 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3498 // The childObject has a reference to a different QObject. We want to ensure
3499 // that the different item will not be cleaned up until required. IE, the childObject
3500 // has implicit ownership of the constructed QObject.
3501 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3502 QObject *object = component.create();
3503 QVERIFY(object != 0);
3504 QMetaObject::invokeMethod(object, "assignCircular");
3505 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3506 QObject *rootObject = object->property("vp").value<QObject*>();
3507 QVERIFY(rootObject != 0);
3508 QObject *childObject = rootObject->findChild<QObject*>("text");
3509 QVERIFY(childObject != 0);
3510 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3511 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3512 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3513 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3514 QVERIFY(!qobjectGuard.isNull());
3515 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3516 QVERIFY(!qobjectGuard.isNull());
3517 QMetaObject::invokeMethod(object, "deassignCircular");
3518 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3519 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3523 void tst_qdeclarativeecmascript::propertyVarReparent()
3525 // ensure that nothing breaks if we re-parent objects
3526 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3527 QObject *object = component.create();
3528 QVERIFY(object != 0);
3529 QMetaObject::invokeMethod(object, "assignVarProp");
3530 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3531 QObject *rect = object->property("vp").value<QObject*>();
3532 QObject *text = rect->findChild<QObject*>("textOne");
3533 QObject *text2 = rect->findChild<QObject*>("textTwo");
3534 QWeakPointer<QObject> rectGuard(rect);
3535 QWeakPointer<QObject> textGuard(text);
3536 QWeakPointer<QObject> text2Guard(text2);
3537 QVERIFY(!rectGuard.isNull());
3538 QVERIFY(!textGuard.isNull());
3539 QVERIFY(!text2Guard.isNull());
3540 QCOMPARE(text->property("textCanary").toInt(), 11);
3541 QCOMPARE(text2->property("textCanary").toInt(), 12);
3542 // now construct an image which we will reparent.
3543 QMetaObject::invokeMethod(text2, "constructQObject");
3544 QObject *image = text2->property("vp").value<QObject*>();
3545 QWeakPointer<QObject> imageGuard(image);
3546 QVERIFY(!imageGuard.isNull());
3547 QCOMPARE(image->property("imageCanary").toInt(), 13);
3548 // now reparent the "Image" object (currently, it has JS ownership)
3549 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3550 QMetaObject::invokeMethod(text2, "deassignVp");
3551 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3552 QCOMPARE(text->property("textCanary").toInt(), 11);
3553 QCOMPARE(text2->property("textCanary").toInt(), 22);
3554 QVERIFY(!imageGuard.isNull()); // should still be alive.
3555 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3556 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3557 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3558 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3562 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3564 // sometimes reparenting can cause problems
3565 // (eg, if the ctxt is collected, varproperties are no longer available)
3566 // this test ensures that no crash occurs in that situation.
3567 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3568 QObject *object = component.create();
3569 QVERIFY(object != 0);
3570 QMetaObject::invokeMethod(object, "assignVarProp");
3571 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3572 QObject *rect = object->property("vp").value<QObject*>();
3573 QObject *text = rect->findChild<QObject*>("textOne");
3574 QObject *text2 = rect->findChild<QObject*>("textTwo");
3575 QWeakPointer<QObject> rectGuard(rect);
3576 QWeakPointer<QObject> textGuard(text);
3577 QWeakPointer<QObject> text2Guard(text2);
3578 QVERIFY(!rectGuard.isNull());
3579 QVERIFY(!textGuard.isNull());
3580 QVERIFY(!text2Guard.isNull());
3581 QCOMPARE(text->property("textCanary").toInt(), 11);
3582 QCOMPARE(text2->property("textCanary").toInt(), 12);
3583 // now construct an image which we will reparent.
3584 QMetaObject::invokeMethod(text2, "constructQObject");
3585 QObject *image = text2->property("vp").value<QObject*>();
3586 QWeakPointer<QObject> imageGuard(image);
3587 QVERIFY(!imageGuard.isNull());
3588 QCOMPARE(image->property("imageCanary").toInt(), 13);
3589 // now reparent the "Image" object (currently, it has JS ownership)
3590 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3591 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3592 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3593 QVERIFY(!imageGuard.isNull()); // should still be alive.
3594 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3596 QVERIFY(imageGuard.isNull()); // should now be dead.
3599 void tst_qdeclarativeecmascript::propertyVarCircular()
3601 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3602 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3603 QObject *object = component.create();
3604 QVERIFY(object != 0);
3605 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3606 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3607 QCOMPARE(object->property("canaryInt"), QVariant(5));
3608 QVariant canaryResourceVariant = object->property("canaryResource");
3609 QVERIFY(canaryResourceVariant.isValid());
3610 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3611 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3612 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3613 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3614 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3615 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3616 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3617 QCOMPARE(object->property("canaryInt"), QVariant(2));
3618 QCOMPARE(object->property("canaryResource"), QVariant(1));
3619 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3623 void tst_qdeclarativeecmascript::propertyVarCircular2()
3625 // track deletion of JS-owned parent item with Cpp-owned child
3626 // where the child has a var property referencing its parent.
3627 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3628 QObject *object = component.create();
3629 QVERIFY(object != 0);
3630 QMetaObject::invokeMethod(object, "assignCircular");
3631 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3632 QObject *rootObject = object->property("vp").value<QObject*>();
3633 QVERIFY(rootObject != 0);
3634 QObject *childObject = rootObject->findChild<QObject*>("text");
3635 QVERIFY(childObject != 0);
3636 QWeakPointer<QObject> rootObjectTracker(rootObject);
3637 QVERIFY(!rootObjectTracker.isNull());
3638 QWeakPointer<QObject> childObjectTracker(childObject);
3639 QVERIFY(!childObjectTracker.isNull());
3641 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3642 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3643 QMetaObject::invokeMethod(object, "deassignCircular");
3644 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3645 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3646 QVERIFY(childObjectTracker.isNull()); // should have been collected
3650 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3652 *(int*)(parameter) += 1;
3653 qPersistentDispose(object);
3656 void tst_qdeclarativeecmascript::propertyVarInheritance()
3658 int propertyVarWeakRefCallbackCount = 0;
3660 // enforce behaviour regarding element inheritance - ensure handle disposal.
3661 // The particular component under test here has a chain of references.
3662 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3663 QObject *object = component.create();
3664 QVERIFY(object != 0);
3665 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3666 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3667 // we want to be able to track when the varProperties array of the last metaobject is disposed
3668 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3669 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*>();
3670 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3671 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3672 v8::Persistent<v8::Value> icoCanaryHandle;
3673 v8::Persistent<v8::Value> ccoCanaryHandle;
3676 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3677 // public function which can return us a handle to something in the varProperties array.
3678 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3679 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3680 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3681 // as the varproperties array of each vmemo still references the resource.
3682 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3683 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3685 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3687 // now we deassign the var prop, which should trigger collection of item subtrees.
3688 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3689 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3690 // ensure that there are only weak handles to the underlying varProperties array remaining.
3692 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3694 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3695 // to what remains are weak, all varProperties arrays must have been collected.
3698 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3700 int propertyVarWeakRefCallbackCount = 0;
3702 // The particular component under test here does NOT have a chain of references; the
3703 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3704 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3705 QObject *object = component.create();
3706 QVERIFY(object != 0);
3707 QMetaObject::invokeMethod(object, "assignCircular");
3708 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3709 QObject *rootObject = object->property("vp").value<QObject*>();
3710 QVERIFY(rootObject != 0);
3711 QObject *childObject = rootObject->findChild<QObject*>("text");
3712 QVERIFY(childObject != 0);
3713 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3714 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3715 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3718 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3719 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3720 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3722 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3723 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3725 QMetaObject::invokeMethod(object, "deassignCircular");
3726 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3727 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3731 // Ensure that QObject type conversion works on binding assignment
3732 void tst_qdeclarativeecmascript::elementAssign()
3734 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3736 QObject *object = component.create();
3737 QVERIFY(object != 0);
3739 QCOMPARE(object->property("test").toBool(), true);
3745 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3747 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3749 QObject *object = component.create();
3750 QVERIFY(object != 0);
3752 QCOMPARE(object->property("test").toBool(), true);
3758 void tst_qdeclarativeecmascript::objectConversion()
3760 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3762 QObject *object = component.create();
3763 QVERIFY(object != 0);
3765 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3766 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3773 void tst_qdeclarativeecmascript::booleanConversion()
3775 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3777 QObject *object = component.create();
3778 QVERIFY(object != 0);
3780 QCOMPARE(object->property("test_true1").toBool(), true);
3781 QCOMPARE(object->property("test_true2").toBool(), true);
3782 QCOMPARE(object->property("test_true3").toBool(), true);
3783 QCOMPARE(object->property("test_true4").toBool(), true);
3784 QCOMPARE(object->property("test_true5").toBool(), true);
3786 QCOMPARE(object->property("test_false1").toBool(), false);
3787 QCOMPARE(object->property("test_false2").toBool(), false);
3788 QCOMPARE(object->property("test_false3").toBool(), false);
3793 void tst_qdeclarativeecmascript::handleReferenceManagement()
3798 // Linear QObject reference
3799 QDeclarativeEngine hrmEngine;
3800 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3801 QObject *object = component.create();
3802 QVERIFY(object != 0);
3803 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3804 cro->setDtorCount(&dtorCount);
3805 QMetaObject::invokeMethod(object, "createReference");
3807 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3809 hrmEngine.collectGarbage();
3810 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3811 QCOMPARE(dtorCount, 3);
3816 // Circular QObject reference
3817 QDeclarativeEngine hrmEngine;
3818 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3819 QObject *object = component.create();
3820 QVERIFY(object != 0);
3821 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3822 cro->setDtorCount(&dtorCount);
3823 QMetaObject::invokeMethod(object, "circularReference");
3825 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3827 hrmEngine.collectGarbage();
3828 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3829 QCOMPARE(dtorCount, 3);
3834 // Linear handle reference
3835 QDeclarativeEngine hrmEngine;
3836 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3837 QObject *object = component.create();
3838 QVERIFY(object != 0);
3839 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3841 crh->setDtorCount(&dtorCount);
3842 QMetaObject::invokeMethod(object, "createReference");
3843 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3844 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3845 QVERIFY(first != 0);
3846 QVERIFY(second != 0);
3847 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3848 // now we have to reparent second and make second owned by JS.
3849 second->setParent(0);
3850 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3852 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3854 hrmEngine.collectGarbage();
3855 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3856 QCOMPARE(dtorCount, 3);
3861 // Circular handle reference
3862 QDeclarativeEngine hrmEngine;
3863 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3864 QObject *object = component.create();
3865 QVERIFY(object != 0);
3866 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3868 crh->setDtorCount(&dtorCount);
3869 QMetaObject::invokeMethod(object, "circularReference");
3870 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3871 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3872 QVERIFY(first != 0);
3873 QVERIFY(second != 0);
3874 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3875 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3876 // now we have to reparent and change ownership.
3877 first->setParent(0);
3878 second->setParent(0);
3879 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3880 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3882 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3884 hrmEngine.collectGarbage();
3885 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3886 QCOMPARE(dtorCount, 3);
3891 // multiple engine interaction - linear reference
3892 QDeclarativeEngine hrmEngine1;
3893 QDeclarativeEngine hrmEngine2;
3894 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3895 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3896 QObject *object1 = component1.create();
3897 QObject *object2 = component2.create();
3898 QVERIFY(object1 != 0);
3899 QVERIFY(object2 != 0);
3900 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3901 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3904 crh1->setDtorCount(&dtorCount);
3905 crh2->setDtorCount(&dtorCount);
3906 QMetaObject::invokeMethod(object1, "createReference");
3907 QMetaObject::invokeMethod(object2, "createReference");
3908 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3909 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3910 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3911 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3912 QVERIFY(first1 != 0);
3913 QVERIFY(second1 != 0);
3914 QVERIFY(first2 != 0);
3915 QVERIFY(second2 != 0);
3916 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3917 // now we have to reparent second2 and make second2 owned by JS.
3918 second2->setParent(0);
3919 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3921 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3922 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3925 hrmEngine1.collectGarbage();
3926 hrmEngine2.collectGarbage();
3927 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3928 QCOMPARE(dtorCount, 6);
3933 // multiple engine interaction - circular reference
3934 QDeclarativeEngine hrmEngine1;
3935 QDeclarativeEngine hrmEngine2;
3936 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3937 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3938 QObject *object1 = component1.create();
3939 QObject *object2 = component2.create();
3940 QVERIFY(object1 != 0);
3941 QVERIFY(object2 != 0);
3942 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3943 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3946 crh1->setDtorCount(&dtorCount);
3947 crh2->setDtorCount(&dtorCount);
3948 QMetaObject::invokeMethod(object1, "createReference");
3949 QMetaObject::invokeMethod(object2, "createReference");
3950 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3951 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3952 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3953 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3954 QVERIFY(first1 != 0);
3955 QVERIFY(second1 != 0);
3956 QVERIFY(first2 != 0);
3957 QVERIFY(second2 != 0);
3958 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3959 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3960 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3961 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3962 // now we have to reparent and change ownership to JS.
3963 first1->setParent(0);
3964 second1->setParent(0);
3965 first2->setParent(0);
3966 second2->setParent(0);
3967 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3968 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3969 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3970 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3972 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3973 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3976 hrmEngine1.collectGarbage();
3977 hrmEngine2.collectGarbage();
3978 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3979 QCOMPARE(dtorCount, 6);
3984 // multiple engine interaction - linear reference with engine deletion
3985 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3986 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3987 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3988 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3989 QObject *object1 = component1.create();
3990 QObject *object2 = component2.create();
3991 QVERIFY(object1 != 0);
3992 QVERIFY(object2 != 0);
3993 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3994 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3997 crh1->setDtorCount(&dtorCount);
3998 crh2->setDtorCount(&dtorCount);
3999 QMetaObject::invokeMethod(object1, "createReference");
4000 QMetaObject::invokeMethod(object2, "createReference");
4001 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4002 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4003 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4004 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4005 QVERIFY(first1 != 0);
4006 QVERIFY(second1 != 0);
4007 QVERIFY(first2 != 0);
4008 QVERIFY(second2 != 0);
4009 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4010 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4011 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4012 // now we have to reparent and change ownership to JS.
4013 first1->setParent(crh1);
4014 second1->setParent(0);
4015 first2->setParent(0);
4016 second2->setParent(0);
4017 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4018 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4019 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4021 QCOMPARE(dtorCount, 0);
4024 QCOMPARE(dtorCount, 0);
4027 hrmEngine1->collectGarbage();
4028 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4029 QCOMPARE(dtorCount, 6);
4034 void tst_qdeclarativeecmascript::stringArg()
4036 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4037 QObject *object = component.create();
4038 QVERIFY(object != 0);
4039 QMetaObject::invokeMethod(object, "success");
4040 QVERIFY(object->property("returnValue").toBool());
4042 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4043 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4044 QMetaObject::invokeMethod(object, "failure");
4045 QVERIFY(object->property("returnValue").toBool());
4050 void tst_qdeclarativeecmascript::readonlyDeclaration()
4052 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4054 QObject *object = component.create();
4055 QVERIFY(object != 0);
4057 QCOMPARE(object->property("test").toBool(), true);
4062 Q_DECLARE_METATYPE(QList<int>)
4063 Q_DECLARE_METATYPE(QList<qreal>)
4064 Q_DECLARE_METATYPE(QList<bool>)
4065 Q_DECLARE_METATYPE(QList<QString>)
4066 Q_DECLARE_METATYPE(QList<QUrl>)
4067 void tst_qdeclarativeecmascript::sequenceConversionRead()
4070 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4071 QDeclarativeComponent component(&engine, qmlFile);
4072 QObject *object = component.create();
4073 QVERIFY(object != 0);
4074 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4077 QMetaObject::invokeMethod(object, "readSequences");
4078 QList<int> intList; intList << 1 << 2 << 3 << 4;
4079 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4080 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4081 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4082 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4083 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4084 QList<bool> boolList; boolList << true << false << true << false;
4085 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4086 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4087 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4088 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4089 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4090 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4091 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4092 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4093 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4094 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4095 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4097 QMetaObject::invokeMethod(object, "readSequenceElements");
4098 QCOMPARE(object->property("intVal").toInt(), 2);
4099 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4100 QCOMPARE(object->property("boolVal").toBool(), false);
4101 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4102 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4103 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4105 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4106 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4108 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4109 QDeclarativeProperty seqProp(seq, "intListProperty");
4110 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4111 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4112 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4114 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4115 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4121 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4122 QDeclarativeComponent component(&engine, qmlFile);
4123 QObject *object = component.create();
4124 QVERIFY(object != 0);
4125 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4128 // we haven't registered QList<QPoint> as a sequence type.
4129 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4130 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4131 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4132 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4134 QMetaObject::invokeMethod(object, "performTest");
4136 // QList<QPoint> has not been registered as a sequence type.
4137 QCOMPARE(object->property("pointListLength").toInt(), 0);
4138 QVERIFY(!object->property("pointList").isValid());
4139 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4140 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4141 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4147 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4150 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4151 QDeclarativeComponent component(&engine, qmlFile);
4152 QObject *object = component.create();
4153 QVERIFY(object != 0);
4154 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4157 QMetaObject::invokeMethod(object, "writeSequences");
4158 QCOMPARE(object->property("success").toBool(), true);
4160 QMetaObject::invokeMethod(object, "writeSequenceElements");
4161 QCOMPARE(object->property("success").toBool(), true);
4163 QMetaObject::invokeMethod(object, "writeOtherElements");
4164 QCOMPARE(object->property("success").toBool(), true);
4166 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4167 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4173 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4174 QDeclarativeComponent component(&engine, qmlFile);
4175 QObject *object = component.create();
4176 QVERIFY(object != 0);
4177 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4180 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4181 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4182 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4184 QMetaObject::invokeMethod(object, "performTest");
4186 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4187 QCOMPARE(seq->pointListProperty(), pointList);
4193 void tst_qdeclarativeecmascript::sequenceConversionArray()
4195 // ensure that in JS the returned sequences act just like normal JS Arrays.
4196 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4197 QDeclarativeComponent component(&engine, qmlFile);
4198 QObject *object = component.create();
4199 QVERIFY(object != 0);
4200 //QMetaObject::invokeMethod(object, "indexedAccess");
4201 //QVERIFY(object->property("success").toBool());
4202 //QMetaObject::invokeMethod(object, "arrayOperations");
4203 //QVERIFY(object->property("success").toBool());
4204 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4205 QVERIFY(object->property("success").toBool());
4206 //QMetaObject::invokeMethod(object, "testReferenceDeletion");
4207 //QCOMPARE(object->property("referenceDeletion").toBool(), true);
4211 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4213 // ensure that sequence conversion operations work correctly in a worker thread
4214 // and that serialisation between the main and worker thread succeeds.
4215 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4216 QDeclarativeComponent component(&engine, qmlFile);
4217 QObject *object = component.create();
4218 QVERIFY(object != 0);
4220 QMetaObject::invokeMethod(object, "testIntSequence");
4221 QTRY_VERIFY(object->property("finished").toBool());
4222 QVERIFY(object->property("success").toBool());
4224 QMetaObject::invokeMethod(object, "testQrealSequence");
4225 QTRY_VERIFY(object->property("finished").toBool());
4226 QVERIFY(object->property("success").toBool());
4228 QMetaObject::invokeMethod(object, "testBoolSequence");
4229 QTRY_VERIFY(object->property("finished").toBool());
4230 QVERIFY(object->property("success").toBool());
4232 QMetaObject::invokeMethod(object, "testStringSequence");
4233 QTRY_VERIFY(object->property("finished").toBool());
4234 QVERIFY(object->property("success").toBool());
4236 QMetaObject::invokeMethod(object, "testQStringSequence");
4237 QTRY_VERIFY(object->property("finished").toBool());
4238 QVERIFY(object->property("success").toBool());
4240 QMetaObject::invokeMethod(object, "testUrlSequence");
4241 QTRY_VERIFY(object->property("finished").toBool());
4242 QVERIFY(object->property("success").toBool());
4244 QMetaObject::invokeMethod(object, "testVariantSequence");
4245 QTRY_VERIFY(object->property("finished").toBool());
4246 QVERIFY(object->property("success").toBool());
4251 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4254 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4255 QDeclarativeComponent component(&engine, qmlFile);
4256 QObject *object = component.create();
4257 QVERIFY(object != 0);
4258 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4259 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4260 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4261 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4262 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4267 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4268 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4269 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4270 QDeclarativeComponent component(&engine, qmlFile);
4271 QObject *object = component.create();
4272 QVERIFY(object != 0);
4277 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4279 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4280 QDeclarativeComponent component(&engine, qmlFile);
4281 QObject *object = component.create();
4282 QVERIFY(object != 0);
4283 QMetaObject::invokeMethod(object, "testCopySequences");
4284 QCOMPARE(object->property("success").toBool(), true);
4285 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4286 QCOMPARE(object->property("success").toBool(), true);
4287 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4288 QCOMPARE(object->property("success").toBool(), true);
4292 // Test that assigning a null object works
4293 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4294 void tst_qdeclarativeecmascript::nullObjectBinding()
4296 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4298 QObject *object = component.create();
4299 QVERIFY(object != 0);
4301 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4306 // Test that bindings don't evaluate once the engine has been destroyed
4307 void tst_qdeclarativeecmascript::deletedEngine()
4309 QDeclarativeEngine *engine = new QDeclarativeEngine;
4310 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4312 QObject *object = component.create();
4313 QVERIFY(object != 0);
4315 QCOMPARE(object->property("a").toInt(), 39);
4316 object->setProperty("b", QVariant(9));
4317 QCOMPARE(object->property("a").toInt(), 117);
4321 QCOMPARE(object->property("a").toInt(), 117);
4322 object->setProperty("b", QVariant(10));
4323 QCOMPARE(object->property("a").toInt(), 117);
4328 // Test the crashing part of QTBUG-9705
4329 void tst_qdeclarativeecmascript::libraryScriptAssert()
4331 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4333 QObject *object = component.create();
4334 QVERIFY(object != 0);
4339 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4341 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4343 QObject *object = component.create();
4344 QVERIFY(object != 0);
4346 QCOMPARE(object->property("test1").toInt(), 10);
4347 QCOMPARE(object->property("test2").toInt(), 11);
4349 object->setProperty("runTest", true);
4351 QCOMPARE(object->property("test1"), QVariant());
4352 QCOMPARE(object->property("test2"), QVariant());
4358 void tst_qdeclarativeecmascript::qtbug_9792()
4360 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4362 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4364 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4365 QVERIFY(object != 0);
4367 QString message = QString(QLatin1String("Hello world! (%1:%2)")).arg(TEST_FILE("qtbug_9792.qml").toString()).arg(4);
4368 QTest::ignoreMessage(QtDebugMsg, qPrintable(message));
4369 object->basicSignal();
4373 transientErrorsMsgCount = 0;
4374 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4376 object->basicSignal();
4378 qInstallMsgHandler(old);
4380 QCOMPARE(transientErrorsMsgCount, 0);
4385 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4386 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4388 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4390 QObject *o = component.create();
4393 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4394 QVERIFY(nested != 0);
4396 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4399 nested = qvariant_cast<QObject *>(o->property("object"));
4400 QVERIFY(nested == 0);
4402 // If the bug is present, the next line will crash
4406 // Test that we shut down without stupid warnings
4407 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4410 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4412 QObject *o = component.create();
4414 transientErrorsMsgCount = 0;
4415 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4419 qInstallMsgHandler(old);
4421 QCOMPARE(transientErrorsMsgCount, 0);
4426 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4428 QObject *o = component.create();
4430 transientErrorsMsgCount = 0;
4431 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4435 qInstallMsgHandler(old);
4437 QCOMPARE(transientErrorsMsgCount, 0);
4441 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4444 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4446 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4449 QVERIFY(o->objectProperty() != 0);
4451 o->setProperty("runTest", true);
4453 QVERIFY(o->objectProperty() == 0);
4459 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4461 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4464 QVERIFY(o->objectProperty() == 0);
4470 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4472 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4474 QString url = component.url().toString();
4475 QString warning = url + ":4: Unable to assign a function to a property.";
4476 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4478 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4481 QVERIFY(!o->property("a").isValid());
4486 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4488 QFETCH(QString, triggerProperty);
4490 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4491 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4493 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4495 QVERIFY(!o->property("a").isValid());
4497 o->setProperty("aNumber", QVariant(5));
4498 o->setProperty(triggerProperty.toUtf8().constData(), true);
4499 QCOMPARE(o->property("a"), QVariant(50));
4501 o->setProperty("aNumber", QVariant(10));
4502 QCOMPARE(o->property("a"), QVariant(100));
4507 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4509 QTest::addColumn<QString>("triggerProperty");
4511 QTest::newRow("assign to property") << "assignToProperty";
4512 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4514 QTest::newRow("assign to value type") << "assignToValueType";
4516 QTest::newRow("use 'this'") << "assignWithThis";
4517 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4520 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4522 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4523 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4525 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4527 QVERIFY(!o->property("a").isValid());
4529 o->setProperty("assignFuncWithoutReturn", true);
4530 QVERIFY(!o->property("a").isValid());
4532 QString url = component.url().toString();
4533 QString warning = url + ":67: Unable to assign QString to int";
4534 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4535 o->setProperty("assignWrongType", true);
4537 warning = url + ":71: Unable to assign QString to int";
4538 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4539 o->setProperty("assignWrongTypeToValueType", true);
4544 void tst_qdeclarativeecmascript::eval()
4546 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4548 QObject *o = component.create();
4551 QCOMPARE(o->property("test1").toBool(), true);
4552 QCOMPARE(o->property("test2").toBool(), true);
4553 QCOMPARE(o->property("test3").toBool(), true);
4554 QCOMPARE(o->property("test4").toBool(), true);
4555 QCOMPARE(o->property("test5").toBool(), true);
4560 void tst_qdeclarativeecmascript::function()
4562 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4564 QObject *o = component.create();
4567 QCOMPARE(o->property("test1").toBool(), true);
4568 QCOMPARE(o->property("test2").toBool(), true);
4569 QCOMPARE(o->property("test3").toBool(), true);
4574 // Test the "Qt.include" method
4575 void tst_qdeclarativeecmascript::include()
4577 // Non-library relative include
4579 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4580 QObject *o = component.create();
4583 QCOMPARE(o->property("test0").toInt(), 99);
4584 QCOMPARE(o->property("test1").toBool(), true);
4585 QCOMPARE(o->property("test2").toBool(), true);
4586 QCOMPARE(o->property("test2_1").toBool(), true);
4587 QCOMPARE(o->property("test3").toBool(), true);
4588 QCOMPARE(o->property("test3_1").toBool(), true);
4593 // Library relative include
4595 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4596 QObject *o = component.create();
4599 QCOMPARE(o->property("test0").toInt(), 99);
4600 QCOMPARE(o->property("test1").toBool(), true);
4601 QCOMPARE(o->property("test2").toBool(), true);
4602 QCOMPARE(o->property("test2_1").toBool(), true);
4603 QCOMPARE(o->property("test3").toBool(), true);
4604 QCOMPARE(o->property("test3_1").toBool(), true);
4611 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4612 QObject *o = component.create();
4615 QCOMPARE(o->property("test1").toBool(), true);
4616 QCOMPARE(o->property("test2").toBool(), true);
4617 QCOMPARE(o->property("test3").toBool(), true);
4618 QCOMPARE(o->property("test4").toBool(), true);
4619 QCOMPARE(o->property("test5").toBool(), true);
4620 QCOMPARE(o->property("test6").toBool(), true);
4625 // Including file with ".pragma library"
4627 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4628 QObject *o = component.create();
4630 QCOMPARE(o->property("test1").toInt(), 100);
4637 TestHTTPServer server(8111);
4638 QVERIFY(server.isValid());
4639 server.serveDirectory(TESTDATA(""));
4641 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4642 QObject *o = component.create();
4645 QTRY_VERIFY(o->property("done").toBool() == true);
4646 QTRY_VERIFY(o->property("done2").toBool() == true);
4648 QCOMPARE(o->property("test1").toBool(), true);
4649 QCOMPARE(o->property("test2").toBool(), true);
4650 QCOMPARE(o->property("test3").toBool(), true);
4651 QCOMPARE(o->property("test4").toBool(), true);
4652 QCOMPARE(o->property("test5").toBool(), true);
4654 QCOMPARE(o->property("test6").toBool(), true);
4655 QCOMPARE(o->property("test7").toBool(), true);
4656 QCOMPARE(o->property("test8").toBool(), true);
4657 QCOMPARE(o->property("test9").toBool(), true);
4658 QCOMPARE(o->property("test10").toBool(), true);
4665 TestHTTPServer server(8111);
4666 QVERIFY(server.isValid());
4667 server.serveDirectory(TESTDATA(""));
4669 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4670 QObject *o = component.create();
4673 QTRY_VERIFY(o->property("done").toBool() == true);
4675 QCOMPARE(o->property("test1").toBool(), true);
4676 QCOMPARE(o->property("test2").toBool(), true);
4677 QCOMPARE(o->property("test3").toBool(), true);
4683 void tst_qdeclarativeecmascript::signalHandlers()
4685 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4686 QObject *o = component.create();
4689 QVERIFY(o->property("count").toInt() == 0);
4690 QMetaObject::invokeMethod(o, "testSignalCall");
4691 QCOMPARE(o->property("count").toInt(), 1);
4693 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4694 QCOMPARE(o->property("count").toInt(), 1);
4695 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4697 QVERIFY(o->property("funcCount").toInt() == 0);
4698 QMetaObject::invokeMethod(o, "testSignalConnection");
4699 QCOMPARE(o->property("funcCount").toInt(), 1);
4701 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4702 QCOMPARE(o->property("funcCount").toInt(), 2);
4704 QMetaObject::invokeMethod(o, "testSignalDefined");
4705 QCOMPARE(o->property("definedResult").toBool(), true);
4707 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4708 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4713 void tst_qdeclarativeecmascript::qtbug_10696()
4715 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4716 QObject *o = component.create();
4721 void tst_qdeclarativeecmascript::qtbug_11606()
4723 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4724 QObject *o = component.create();
4726 QCOMPARE(o->property("test").toBool(), true);
4730 void tst_qdeclarativeecmascript::qtbug_11600()
4732 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4733 QObject *o = component.create();
4735 QCOMPARE(o->property("test").toBool(), true);
4739 // Reading and writing non-scriptable properties should fail
4740 void tst_qdeclarativeecmascript::nonscriptable()
4742 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4743 QObject *o = component.create();
4745 QCOMPARE(o->property("readOk").toBool(), true);
4746 QCOMPARE(o->property("writeOk").toBool(), true);
4750 // deleteLater() should not be callable from QML
4751 void tst_qdeclarativeecmascript::deleteLater()
4753 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4754 QObject *o = component.create();
4756 QCOMPARE(o->property("test").toBool(), true);
4760 void tst_qdeclarativeecmascript::in()
4762 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4763 QObject *o = component.create();
4765 QCOMPARE(o->property("test1").toBool(), true);
4766 QCOMPARE(o->property("test2").toBool(), true);
4770 void tst_qdeclarativeecmascript::typeOf()
4772 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4773 QObject *o = component.create();
4775 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4776 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4777 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4778 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4779 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4780 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4781 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4782 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4783 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4784 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4789 void tst_qdeclarativeecmascript::sharedAttachedObject()
4791 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4792 QObject *o = component.create();
4794 QCOMPARE(o->property("test1").toBool(), true);
4795 QCOMPARE(o->property("test2").toBool(), true);
4800 void tst_qdeclarativeecmascript::objectName()
4802 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4803 QObject *o = component.create();
4806 QCOMPARE(o->property("test1").toString(), QString("hello"));
4807 QCOMPARE(o->property("test2").toString(), QString("ell"));
4809 o->setObjectName("world");
4811 QCOMPARE(o->property("test1").toString(), QString("world"));
4812 QCOMPARE(o->property("test2").toString(), QString("orl"));
4817 void tst_qdeclarativeecmascript::writeRemovesBinding()
4819 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4820 QObject *o = component.create();
4823 QCOMPARE(o->property("test").toBool(), true);
4828 // Test bindings assigned to alias properties actually assign to the alias' target
4829 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4831 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4832 QObject *o = component.create();
4835 QCOMPARE(o->property("test").toBool(), true);
4840 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4841 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4844 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4845 QObject *o = component.create();
4848 QCOMPARE(o->property("test").toBool(), true);
4854 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4855 QObject *o = component.create();
4858 QCOMPARE(o->property("test").toBool(), true);
4864 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4865 QObject *o = component.create();
4868 QCOMPARE(o->property("test").toBool(), true);
4874 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4875 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4878 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4879 QObject *o = component.create();
4882 QCOMPARE(o->property("test").toBool(), true);
4888 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4889 QObject *o = component.create();
4892 QCOMPARE(o->property("test").toBool(), true);
4898 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4899 QObject *o = component.create();
4902 QCOMPARE(o->property("test").toBool(), true);
4908 // Allow an alais to a composite element
4910 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4912 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4914 QObject *object = component.create();
4915 QVERIFY(object != 0);
4920 void tst_qdeclarativeecmascript::qtbug_20344()
4922 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
4924 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
4925 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
4927 QObject *object = component.create();
4928 QVERIFY(object != 0);
4933 void tst_qdeclarativeecmascript::revisionErrors()
4936 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4937 QString url = component.url().toString();
4939 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4940 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4941 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4943 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4944 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4945 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4946 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4947 QVERIFY(object != 0);
4951 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4952 QString url = component.url().toString();
4954 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4955 // method2, prop2 from MyRevisionedClass not available
4956 // method4, prop4 from MyRevisionedSubclass not available
4957 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4958 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4959 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4960 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4961 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4963 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4964 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4965 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4966 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4967 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4968 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4969 QVERIFY(object != 0);
4973 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4974 QString url = component.url().toString();
4976 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4977 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4978 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4979 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4980 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4981 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4982 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4983 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4984 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4985 QVERIFY(object != 0);
4990 void tst_qdeclarativeecmascript::revision()
4993 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4994 QString url = component.url().toString();
4996 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4997 QVERIFY(object != 0);
5001 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5002 QString url = component.url().toString();
5004 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5005 QVERIFY(object != 0);
5009 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5010 QString url = component.url().toString();
5012 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5013 QVERIFY(object != 0);
5016 // Test that non-root classes can resolve revisioned methods
5018 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5020 QObject *object = component.create();
5021 QVERIFY(object != 0);
5022 QCOMPARE(object->property("test").toReal(), 11.);
5027 void tst_qdeclarativeecmascript::realToInt()
5029 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5030 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5031 QVERIFY(object != 0);
5033 QMetaObject::invokeMethod(object, "test1");
5034 QCOMPARE(object->value(), int(4));
5035 QMetaObject::invokeMethod(object, "test2");
5036 QCOMPARE(object->value(), int(8));
5038 void tst_qdeclarativeecmascript::dynamicString()
5040 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5041 QObject *object = component.create();
5042 QVERIFY(object != 0);
5043 QCOMPARE(object->property("stringProperty").toString(),
5044 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5047 void tst_qdeclarativeecmascript::automaticSemicolon()
5049 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5050 QObject *object = component.create();
5051 QVERIFY(object != 0);
5054 void tst_qdeclarativeecmascript::unaryExpression()
5056 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5057 QObject *object = component.create();
5058 QVERIFY(object != 0);
5061 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5062 void tst_qdeclarativeecmascript::doubleEvaluate()
5064 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5065 QObject *object = component.create();
5066 QVERIFY(object != 0);
5067 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5069 QCOMPARE(wc->count(), 1);
5071 wc->setProperty("x", 9);
5073 QCOMPARE(wc->count(), 2);
5078 static QStringList messages;
5079 static void captureMsgHandler(QtMsgType, const char *msg)
5081 messages.append(QLatin1String(msg));
5084 void tst_qdeclarativeecmascript::nonNotifyable()
5086 QV4Compiler::enableV4(false);
5087 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5088 QV4Compiler::enableV4(true);
5090 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5092 QObject *object = component.create();
5093 qInstallMsgHandler(old);
5095 QVERIFY(object != 0);
5097 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5098 component.url().toString() +
5099 QLatin1String(":5 depends on non-NOTIFYable properties:");
5100 QString expected2 = QLatin1String(" ") +
5101 QLatin1String(object->metaObject()->className()) +
5102 QLatin1String("::value");
5104 QCOMPARE(messages.length(), 2);
5105 QCOMPARE(messages.at(0), expected1);
5106 QCOMPARE(messages.at(1), expected2);
5111 void tst_qdeclarativeecmascript::forInLoop()
5113 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5114 QObject *object = component.create();
5115 QVERIFY(object != 0);
5117 QMetaObject::invokeMethod(object, "listProperty");
5119 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5120 QCOMPARE(r.size(), 3);
5121 QCOMPARE(r[0],QLatin1String("0=obj1"));
5122 QCOMPARE(r[1],QLatin1String("1=obj2"));
5123 QCOMPARE(r[2],QLatin1String("2=obj3"));
5125 //TODO: should test for in loop for other objects (such as QObjects) as well.
5130 // An object the binding depends on is deleted while the binding is still running
5131 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5133 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5134 QObject *object = component.create();
5135 QVERIFY(object != 0);
5139 QTEST_MAIN(tst_qdeclarativeecmascript)
5141 #include "tst_qdeclarativeecmascript.moc"