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);
1646 // Aliases to variant properties should work
1647 void tst_qdeclarativeecmascript::qtbug_22464()
1649 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1650 QObject *object = component.create();
1651 QVERIFY(object != 0);
1653 QCOMPARE(object->property("test").toBool(), true);
1659 void tst_qdeclarativeecmascript::bug1()
1661 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1662 QObject *object = component.create();
1663 QVERIFY(object != 0);
1665 QCOMPARE(object->property("test").toInt(), 14);
1667 object->setProperty("a", 11);
1669 QCOMPARE(object->property("test").toInt(), 3);
1671 object->setProperty("b", true);
1673 QCOMPARE(object->property("test").toInt(), 9);
1678 void tst_qdeclarativeecmascript::bug2()
1680 QDeclarativeComponent component(&engine);
1681 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1683 QObject *object = component.create();
1684 QVERIFY(object != 0);
1689 // Don't crash in createObject when the component has errors.
1690 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1692 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1693 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1694 QVERIFY(object != 0);
1696 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1697 QMetaObject::invokeMethod(object, "dontCrash");
1698 QObject *created = object->objectProperty();
1699 QVERIFY(created == 0);
1704 // ownership transferred to JS, ensure that GC runs the dtor
1705 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1708 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1710 // allow the engine to go out of scope too.
1712 QDeclarativeEngine dcoEngine;
1713 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1714 QObject *object = component.create();
1715 QVERIFY(object != 0);
1716 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1717 QVERIFY(mdcdo != 0);
1718 mdcdo->setDtorCount(&dtorCount);
1720 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1721 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1723 // we do this once manually, but it should be done automatically
1724 // when the engine goes out of scope (since it should gc in dtor)
1725 QMetaObject::invokeMethod(object, "performGc");
1728 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1734 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1735 QCOMPARE(dtorCount, expectedDtorCount);
1739 void tst_qdeclarativeecmascript::regExpBug()
1741 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1742 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1743 QVERIFY(object != 0);
1744 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1748 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1750 QString functionSource = QLatin1String("(function(object) { return ") +
1751 QLatin1String(source) + QLatin1String(" })");
1753 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1756 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1757 if (function.IsEmpty())
1759 v8::Handle<v8::Value> args[] = { o };
1760 function->Call(engine->global(), 1, args);
1761 return tc.HasCaught();
1764 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1765 const char *source, v8::Handle<v8::Value> result)
1767 QString functionSource = QLatin1String("(function(object) { return ") +
1768 QLatin1String(source) + QLatin1String(" })");
1770 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1773 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1774 if (function.IsEmpty())
1776 v8::Handle<v8::Value> args[] = { o };
1778 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1783 return value->StrictEquals(result);
1786 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1789 QString functionSource = QLatin1String("(function(object) { return ") +
1790 QLatin1String(source) + QLatin1String(" })");
1792 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1794 return v8::Handle<v8::Value>();
1795 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1796 if (function.IsEmpty())
1797 return v8::Handle<v8::Value>();
1798 v8::Handle<v8::Value> args[] = { o };
1800 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1803 return v8::Handle<v8::Value>();
1807 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1808 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1809 #define EVALUATE(source) evaluate(engine, object, source)
1811 void tst_qdeclarativeecmascript::callQtInvokables()
1813 MyInvokableObject o;
1815 QDeclarativeEngine qmlengine;
1816 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1818 QV8Engine *engine = ep->v8engine();
1820 v8::HandleScope handle_scope;
1821 v8::Context::Scope scope(engine->context());
1823 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1825 // Non-existent methods
1827 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1828 QCOMPARE(o.error(), false);
1829 QCOMPARE(o.invoked(), -1);
1830 QCOMPARE(o.actuals().count(), 0);
1833 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1834 QCOMPARE(o.error(), false);
1835 QCOMPARE(o.invoked(), -1);
1836 QCOMPARE(o.actuals().count(), 0);
1838 // Insufficient arguments
1840 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1841 QCOMPARE(o.error(), false);
1842 QCOMPARE(o.invoked(), -1);
1843 QCOMPARE(o.actuals().count(), 0);
1846 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1847 QCOMPARE(o.error(), false);
1848 QCOMPARE(o.invoked(), -1);
1849 QCOMPARE(o.actuals().count(), 0);
1851 // Excessive arguments
1853 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1854 QCOMPARE(o.error(), false);
1855 QCOMPARE(o.invoked(), 8);
1856 QCOMPARE(o.actuals().count(), 1);
1857 QCOMPARE(o.actuals().at(0), QVariant(10));
1860 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1861 QCOMPARE(o.error(), false);
1862 QCOMPARE(o.invoked(), 9);
1863 QCOMPARE(o.actuals().count(), 2);
1864 QCOMPARE(o.actuals().at(0), QVariant(10));
1865 QCOMPARE(o.actuals().at(1), QVariant(11));
1867 // Test return types
1869 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1870 QCOMPARE(o.error(), false);
1871 QCOMPARE(o.invoked(), 0);
1872 QCOMPARE(o.actuals().count(), 0);
1875 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1876 QCOMPARE(o.error(), false);
1877 QCOMPARE(o.invoked(), 1);
1878 QCOMPARE(o.actuals().count(), 0);
1881 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1882 QCOMPARE(o.error(), false);
1883 QCOMPARE(o.invoked(), 2);
1884 QCOMPARE(o.actuals().count(), 0);
1888 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1889 QVERIFY(!ret.IsEmpty());
1890 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1891 QCOMPARE(o.error(), false);
1892 QCOMPARE(o.invoked(), 3);
1893 QCOMPARE(o.actuals().count(), 0);
1898 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1899 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1900 QCOMPARE(o.error(), false);
1901 QCOMPARE(o.invoked(), 4);
1902 QCOMPARE(o.actuals().count(), 0);
1906 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1907 QCOMPARE(o.error(), false);
1908 QCOMPARE(o.invoked(), 5);
1909 QCOMPARE(o.actuals().count(), 0);
1913 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1914 QVERIFY(ret->IsString());
1915 QCOMPARE(engine->toString(ret), QString("Hello world"));
1916 QCOMPARE(o.error(), false);
1917 QCOMPARE(o.invoked(), 6);
1918 QCOMPARE(o.actuals().count(), 0);
1922 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1923 QCOMPARE(o.error(), false);
1924 QCOMPARE(o.invoked(), 7);
1925 QCOMPARE(o.actuals().count(), 0);
1929 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1930 QCOMPARE(o.error(), false);
1931 QCOMPARE(o.invoked(), 8);
1932 QCOMPARE(o.actuals().count(), 1);
1933 QCOMPARE(o.actuals().at(0), QVariant(94));
1936 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1937 QCOMPARE(o.error(), false);
1938 QCOMPARE(o.invoked(), 8);
1939 QCOMPARE(o.actuals().count(), 1);
1940 QCOMPARE(o.actuals().at(0), QVariant(94));
1943 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1944 QCOMPARE(o.error(), false);
1945 QCOMPARE(o.invoked(), 8);
1946 QCOMPARE(o.actuals().count(), 1);
1947 QCOMPARE(o.actuals().at(0), QVariant(0));
1950 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1951 QCOMPARE(o.error(), false);
1952 QCOMPARE(o.invoked(), 8);
1953 QCOMPARE(o.actuals().count(), 1);
1954 QCOMPARE(o.actuals().at(0), QVariant(0));
1957 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1958 QCOMPARE(o.error(), false);
1959 QCOMPARE(o.invoked(), 8);
1960 QCOMPARE(o.actuals().count(), 1);
1961 QCOMPARE(o.actuals().at(0), QVariant(0));
1964 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1965 QCOMPARE(o.error(), false);
1966 QCOMPARE(o.invoked(), 8);
1967 QCOMPARE(o.actuals().count(), 1);
1968 QCOMPARE(o.actuals().at(0), QVariant(0));
1971 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1972 QCOMPARE(o.error(), false);
1973 QCOMPARE(o.invoked(), 9);
1974 QCOMPARE(o.actuals().count(), 2);
1975 QCOMPARE(o.actuals().at(0), QVariant(122));
1976 QCOMPARE(o.actuals().at(1), QVariant(9));
1979 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1980 QCOMPARE(o.error(), false);
1981 QCOMPARE(o.invoked(), 10);
1982 QCOMPARE(o.actuals().count(), 1);
1983 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1986 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1987 QCOMPARE(o.error(), false);
1988 QCOMPARE(o.invoked(), 10);
1989 QCOMPARE(o.actuals().count(), 1);
1990 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1993 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1994 QCOMPARE(o.error(), false);
1995 QCOMPARE(o.invoked(), 10);
1996 QCOMPARE(o.actuals().count(), 1);
1997 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2000 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2001 QCOMPARE(o.error(), false);
2002 QCOMPARE(o.invoked(), 10);
2003 QCOMPARE(o.actuals().count(), 1);
2004 QCOMPARE(o.actuals().at(0), QVariant(0));
2007 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2008 QCOMPARE(o.error(), false);
2009 QCOMPARE(o.invoked(), 10);
2010 QCOMPARE(o.actuals().count(), 1);
2011 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2014 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2015 QCOMPARE(o.error(), false);
2016 QCOMPARE(o.invoked(), 10);
2017 QCOMPARE(o.actuals().count(), 1);
2018 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2021 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2022 QCOMPARE(o.error(), false);
2023 QCOMPARE(o.invoked(), 11);
2024 QCOMPARE(o.actuals().count(), 1);
2025 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2028 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2029 QCOMPARE(o.error(), false);
2030 QCOMPARE(o.invoked(), 11);
2031 QCOMPARE(o.actuals().count(), 1);
2032 QCOMPARE(o.actuals().at(0), QVariant("19"));
2036 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2037 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2038 QCOMPARE(o.error(), false);
2039 QCOMPARE(o.invoked(), 11);
2040 QCOMPARE(o.actuals().count(), 1);
2041 QCOMPARE(o.actuals().at(0), QVariant(expected));
2045 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2046 QCOMPARE(o.error(), false);
2047 QCOMPARE(o.invoked(), 11);
2048 QCOMPARE(o.actuals().count(), 1);
2049 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2052 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2053 QCOMPARE(o.error(), false);
2054 QCOMPARE(o.invoked(), 11);
2055 QCOMPARE(o.actuals().count(), 1);
2056 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2059 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2060 QCOMPARE(o.error(), false);
2061 QCOMPARE(o.invoked(), 12);
2062 QCOMPARE(o.actuals().count(), 1);
2063 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2066 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2067 QCOMPARE(o.error(), false);
2068 QCOMPARE(o.invoked(), 12);
2069 QCOMPARE(o.actuals().count(), 1);
2070 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2073 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2074 QCOMPARE(o.error(), false);
2075 QCOMPARE(o.invoked(), 12);
2076 QCOMPARE(o.actuals().count(), 1);
2077 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2080 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2081 QCOMPARE(o.error(), false);
2082 QCOMPARE(o.invoked(), 12);
2083 QCOMPARE(o.actuals().count(), 1);
2084 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2087 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2088 QCOMPARE(o.error(), false);
2089 QCOMPARE(o.invoked(), 12);
2090 QCOMPARE(o.actuals().count(), 1);
2091 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2094 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2095 QCOMPARE(o.error(), false);
2096 QCOMPARE(o.invoked(), 12);
2097 QCOMPARE(o.actuals().count(), 1);
2098 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2101 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2102 QCOMPARE(o.error(), false);
2103 QCOMPARE(o.invoked(), 13);
2104 QCOMPARE(o.actuals().count(), 1);
2105 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2108 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2109 QCOMPARE(o.error(), false);
2110 QCOMPARE(o.invoked(), 13);
2111 QCOMPARE(o.actuals().count(), 1);
2112 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2115 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2116 QCOMPARE(o.error(), false);
2117 QCOMPARE(o.invoked(), 13);
2118 QCOMPARE(o.actuals().count(), 1);
2119 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2122 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2123 QCOMPARE(o.error(), false);
2124 QCOMPARE(o.invoked(), 13);
2125 QCOMPARE(o.actuals().count(), 1);
2126 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2129 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2130 QCOMPARE(o.error(), false);
2131 QCOMPARE(o.invoked(), 13);
2132 QCOMPARE(o.actuals().count(), 1);
2133 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2136 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2137 QCOMPARE(o.error(), false);
2138 QCOMPARE(o.invoked(), 14);
2139 QCOMPARE(o.actuals().count(), 1);
2140 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2143 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2144 QCOMPARE(o.error(), false);
2145 QCOMPARE(o.invoked(), 14);
2146 QCOMPARE(o.actuals().count(), 1);
2147 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2150 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2151 QCOMPARE(o.error(), false);
2152 QCOMPARE(o.invoked(), 14);
2153 QCOMPARE(o.actuals().count(), 1);
2154 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2157 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2158 QCOMPARE(o.error(), false);
2159 QCOMPARE(o.invoked(), 14);
2160 QCOMPARE(o.actuals().count(), 1);
2161 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2164 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2165 QCOMPARE(o.error(), false);
2166 QCOMPARE(o.invoked(), 15);
2167 QCOMPARE(o.actuals().count(), 2);
2168 QCOMPARE(o.actuals().at(0), QVariant(4));
2169 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2172 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2173 QCOMPARE(o.error(), false);
2174 QCOMPARE(o.invoked(), 15);
2175 QCOMPARE(o.actuals().count(), 2);
2176 QCOMPARE(o.actuals().at(0), QVariant(8));
2177 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2180 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2181 QCOMPARE(o.error(), false);
2182 QCOMPARE(o.invoked(), 15);
2183 QCOMPARE(o.actuals().count(), 2);
2184 QCOMPARE(o.actuals().at(0), QVariant(3));
2185 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2188 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2189 QCOMPARE(o.error(), false);
2190 QCOMPARE(o.invoked(), 15);
2191 QCOMPARE(o.actuals().count(), 2);
2192 QCOMPARE(o.actuals().at(0), QVariant(44));
2193 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2196 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2197 QCOMPARE(o.error(), false);
2198 QCOMPARE(o.invoked(), -1);
2199 QCOMPARE(o.actuals().count(), 0);
2202 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2203 QCOMPARE(o.error(), false);
2204 QCOMPARE(o.invoked(), 16);
2205 QCOMPARE(o.actuals().count(), 1);
2206 QCOMPARE(o.actuals().at(0), QVariant(10));
2209 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2210 QCOMPARE(o.error(), false);
2211 QCOMPARE(o.invoked(), 17);
2212 QCOMPARE(o.actuals().count(), 2);
2213 QCOMPARE(o.actuals().at(0), QVariant(10));
2214 QCOMPARE(o.actuals().at(1), QVariant(11));
2217 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2218 QCOMPARE(o.error(), false);
2219 QCOMPARE(o.invoked(), 18);
2220 QCOMPARE(o.actuals().count(), 1);
2221 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2224 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2225 QCOMPARE(o.error(), false);
2226 QCOMPARE(o.invoked(), 19);
2227 QCOMPARE(o.actuals().count(), 1);
2228 QCOMPARE(o.actuals().at(0), QVariant(9));
2231 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2232 QCOMPARE(o.error(), false);
2233 QCOMPARE(o.invoked(), 20);
2234 QCOMPARE(o.actuals().count(), 2);
2235 QCOMPARE(o.actuals().at(0), QVariant(10));
2236 QCOMPARE(o.actuals().at(1), QVariant(19));
2239 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2240 QCOMPARE(o.error(), false);
2241 QCOMPARE(o.invoked(), 20);
2242 QCOMPARE(o.actuals().count(), 2);
2243 QCOMPARE(o.actuals().at(0), QVariant(10));
2244 QCOMPARE(o.actuals().at(1), QVariant(13));
2247 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2248 QCOMPARE(o.error(), false);
2249 QCOMPARE(o.invoked(), -3);
2250 QCOMPARE(o.actuals().count(), 1);
2251 QCOMPARE(o.actuals().at(0), QVariant(9));
2254 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2255 QCOMPARE(o.error(), false);
2256 QCOMPARE(o.invoked(), 21);
2257 QCOMPARE(o.actuals().count(), 2);
2258 QCOMPARE(o.actuals().at(0), QVariant(9));
2259 QCOMPARE(o.actuals().at(1), QVariant());
2262 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2263 QCOMPARE(o.error(), false);
2264 QCOMPARE(o.invoked(), 21);
2265 QCOMPARE(o.actuals().count(), 2);
2266 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2267 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2270 // QTBUG-13047 (check that you can pass registered object types as args)
2271 void tst_qdeclarativeecmascript::invokableObjectArg()
2273 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2275 QObject *o = component.create();
2277 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2279 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2284 // QTBUG-13047 (check that you can return registered object types from methods)
2285 void tst_qdeclarativeecmascript::invokableObjectRet()
2287 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2289 QObject *o = component.create();
2291 QCOMPARE(o->property("test").toBool(), true);
2296 void tst_qdeclarativeecmascript::listToVariant()
2298 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2300 MyQmlContainer container;
2302 QDeclarativeContext context(engine.rootContext());
2303 context.setContextObject(&container);
2305 QObject *object = component.create(&context);
2306 QVERIFY(object != 0);
2308 QVariant v = object->property("test");
2309 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2310 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2316 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2317 void tst_qdeclarativeecmascript::listAssignment()
2319 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2320 QObject *obj = component.create();
2321 QCOMPARE(obj->property("list1length").toInt(), 2);
2322 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2323 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2324 QCOMPARE(list1.count(&list1), list2.count(&list2));
2325 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2326 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2331 void tst_qdeclarativeecmascript::multiEngineObject()
2334 obj.setStringProperty("Howdy planet");
2336 QDeclarativeEngine e1;
2337 e1.rootContext()->setContextProperty("thing", &obj);
2338 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2340 QDeclarativeEngine e2;
2341 e2.rootContext()->setContextProperty("thing", &obj);
2342 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2344 QObject *o1 = c1.create();
2345 QObject *o2 = c2.create();
2347 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2348 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2354 // Test that references to QObjects are cleanup when the object is destroyed
2355 void tst_qdeclarativeecmascript::deletedObject()
2357 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2359 QObject *object = component.create();
2361 QCOMPARE(object->property("test1").toBool(), true);
2362 QCOMPARE(object->property("test2").toBool(), true);
2363 QCOMPARE(object->property("test3").toBool(), true);
2364 QCOMPARE(object->property("test4").toBool(), true);
2369 void tst_qdeclarativeecmascript::attachedPropertyScope()
2371 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2373 QObject *object = component.create();
2374 QVERIFY(object != 0);
2376 MyQmlAttachedObject *attached =
2377 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2378 QVERIFY(attached != 0);
2380 QCOMPARE(object->property("value2").toInt(), 0);
2382 attached->emitMySignal();
2384 QCOMPARE(object->property("value2").toInt(), 9);
2389 void tst_qdeclarativeecmascript::scriptConnect()
2392 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2394 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2395 QVERIFY(object != 0);
2397 QCOMPARE(object->property("test").toBool(), false);
2398 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2399 QCOMPARE(object->property("test").toBool(), true);
2405 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2407 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2408 QVERIFY(object != 0);
2410 QCOMPARE(object->property("test").toBool(), false);
2411 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2412 QCOMPARE(object->property("test").toBool(), true);
2418 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2420 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2421 QVERIFY(object != 0);
2423 QCOMPARE(object->property("test").toBool(), false);
2424 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2425 QCOMPARE(object->property("test").toBool(), true);
2431 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2433 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2434 QVERIFY(object != 0);
2436 QCOMPARE(object->methodCalled(), false);
2437 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2438 QCOMPARE(object->methodCalled(), true);
2444 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2446 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2447 QVERIFY(object != 0);
2449 QCOMPARE(object->methodCalled(), false);
2450 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2451 QCOMPARE(object->methodCalled(), true);
2457 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2459 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2460 QVERIFY(object != 0);
2462 QCOMPARE(object->property("test").toInt(), 0);
2463 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2464 QCOMPARE(object->property("test").toInt(), 2);
2470 void tst_qdeclarativeecmascript::scriptDisconnect()
2473 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2475 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2476 QVERIFY(object != 0);
2478 QCOMPARE(object->property("test").toInt(), 0);
2479 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2480 QCOMPARE(object->property("test").toInt(), 1);
2481 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2482 QCOMPARE(object->property("test").toInt(), 2);
2483 emit object->basicSignal();
2484 QCOMPARE(object->property("test").toInt(), 2);
2485 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2486 QCOMPARE(object->property("test").toInt(), 2);
2492 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2494 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2495 QVERIFY(object != 0);
2497 QCOMPARE(object->property("test").toInt(), 0);
2498 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2499 QCOMPARE(object->property("test").toInt(), 1);
2500 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2501 QCOMPARE(object->property("test").toInt(), 2);
2502 emit object->basicSignal();
2503 QCOMPARE(object->property("test").toInt(), 2);
2504 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2505 QCOMPARE(object->property("test").toInt(), 2);
2511 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2513 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2514 QVERIFY(object != 0);
2516 QCOMPARE(object->property("test").toInt(), 0);
2517 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2518 QCOMPARE(object->property("test").toInt(), 1);
2519 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2520 QCOMPARE(object->property("test").toInt(), 2);
2521 emit object->basicSignal();
2522 QCOMPARE(object->property("test").toInt(), 2);
2523 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2524 QCOMPARE(object->property("test").toInt(), 3);
2529 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2531 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2532 QVERIFY(object != 0);
2534 QCOMPARE(object->property("test").toInt(), 0);
2535 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2536 QCOMPARE(object->property("test").toInt(), 1);
2537 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2538 QCOMPARE(object->property("test").toInt(), 2);
2539 emit object->basicSignal();
2540 QCOMPARE(object->property("test").toInt(), 2);
2541 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2542 QCOMPARE(object->property("test").toInt(), 3);
2548 class OwnershipObject : public QObject
2552 OwnershipObject() { object = new QObject; }
2554 QPointer<QObject> object;
2557 QObject *getObject() { return object; }
2560 void tst_qdeclarativeecmascript::ownership()
2562 OwnershipObject own;
2563 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2564 context->setContextObject(&own);
2567 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2569 QVERIFY(own.object != 0);
2571 QObject *object = component.create(context);
2573 engine.collectGarbage();
2575 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2577 QVERIFY(own.object == 0);
2582 own.object = new QObject(&own);
2585 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2587 QVERIFY(own.object != 0);
2589 QObject *object = component.create(context);
2591 engine.collectGarbage();
2593 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2595 QVERIFY(own.object != 0);
2603 class CppOwnershipReturnValue : public QObject
2607 CppOwnershipReturnValue() : value(0) {}
2608 ~CppOwnershipReturnValue() { delete value; }
2610 Q_INVOKABLE QObject *create() {
2611 value = new QObject;
2612 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2616 Q_INVOKABLE MyQmlObject *createQmlObject() {
2617 MyQmlObject *rv = new MyQmlObject;
2622 QPointer<QObject> value;
2626 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2627 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2629 CppOwnershipReturnValue source;
2632 QDeclarativeEngine engine;
2633 engine.rootContext()->setContextProperty("source", &source);
2635 QVERIFY(source.value == 0);
2637 QDeclarativeComponent component(&engine);
2638 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2640 QObject *object = component.create();
2642 QVERIFY(object != 0);
2643 QVERIFY(source.value != 0);
2648 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2650 QVERIFY(source.value != 0);
2654 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2656 CppOwnershipReturnValue source;
2659 QDeclarativeEngine engine;
2660 engine.rootContext()->setContextProperty("source", &source);
2662 QVERIFY(source.value == 0);
2664 QDeclarativeComponent component(&engine);
2665 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2667 QObject *object = component.create();
2669 QVERIFY(object != 0);
2670 QVERIFY(source.value != 0);
2675 engine.collectGarbage();
2676 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2678 QVERIFY(source.value == 0);
2681 class QListQObjectMethodsObject : public QObject
2685 QListQObjectMethodsObject() {
2686 m_objects.append(new MyQmlObject());
2687 m_objects.append(new MyQmlObject());
2690 ~QListQObjectMethodsObject() {
2691 qDeleteAll(m_objects);
2695 QList<QObject *> getObjects() { return m_objects; }
2698 QList<QObject *> m_objects;
2701 // Tests that returning a QList<QObject*> from a method works
2702 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2704 QListQObjectMethodsObject obj;
2705 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2706 context->setContextObject(&obj);
2708 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2710 QObject *object = component.create(context);
2712 QCOMPARE(object->property("test").toInt(), 2);
2713 QCOMPARE(object->property("test2").toBool(), true);
2720 void tst_qdeclarativeecmascript::strictlyEquals()
2722 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2724 QObject *object = component.create();
2725 QVERIFY(object != 0);
2727 QCOMPARE(object->property("test1").toBool(), true);
2728 QCOMPARE(object->property("test2").toBool(), true);
2729 QCOMPARE(object->property("test3").toBool(), true);
2730 QCOMPARE(object->property("test4").toBool(), true);
2731 QCOMPARE(object->property("test5").toBool(), true);
2732 QCOMPARE(object->property("test6").toBool(), true);
2733 QCOMPARE(object->property("test7").toBool(), true);
2734 QCOMPARE(object->property("test8").toBool(), true);
2739 void tst_qdeclarativeecmascript::compiled()
2741 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2743 QObject *object = component.create();
2744 QVERIFY(object != 0);
2746 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2747 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2748 QCOMPARE(object->property("test3").toBool(), true);
2749 QCOMPARE(object->property("test4").toBool(), false);
2750 QCOMPARE(object->property("test5").toBool(), false);
2751 QCOMPARE(object->property("test6").toBool(), true);
2753 QCOMPARE(object->property("test7").toInt(), 185);
2754 QCOMPARE(object->property("test8").toInt(), 167);
2755 QCOMPARE(object->property("test9").toBool(), true);
2756 QCOMPARE(object->property("test10").toBool(), false);
2757 QCOMPARE(object->property("test11").toBool(), false);
2758 QCOMPARE(object->property("test12").toBool(), true);
2760 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2761 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2762 QCOMPARE(object->property("test15").toBool(), false);
2763 QCOMPARE(object->property("test16").toBool(), true);
2765 QCOMPARE(object->property("test17").toInt(), 5);
2766 QCOMPARE(object->property("test18").toReal(), qreal(176));
2767 QCOMPARE(object->property("test19").toInt(), 7);
2768 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2769 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2770 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2771 QCOMPARE(object->property("test23").toBool(), true);
2772 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2773 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2778 // Test that numbers assigned in bindings as strings work consistently
2779 void tst_qdeclarativeecmascript::numberAssignment()
2781 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2783 QObject *object = component.create();
2784 QVERIFY(object != 0);
2786 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2787 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2788 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2789 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2790 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2792 QCOMPARE(object->property("test5"), QVariant((int)7));
2793 QCOMPARE(object->property("test6"), QVariant((int)7));
2794 QCOMPARE(object->property("test7"), QVariant((int)6));
2795 QCOMPARE(object->property("test8"), QVariant((int)6));
2797 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2798 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2799 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2800 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2805 void tst_qdeclarativeecmascript::propertySplicing()
2807 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2809 QObject *object = component.create();
2810 QVERIFY(object != 0);
2812 QCOMPARE(object->property("test").toBool(), true);
2818 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2820 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2822 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2823 QVERIFY(object != 0);
2825 MyQmlObject::MyType type;
2826 type.value = 0x8971123;
2827 emit object->signalWithUnknownType(type);
2829 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2831 QCOMPARE(result.value, type.value);
2837 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2839 QTest::addColumn<QString>("expression");
2840 QTest::addColumn<QString>("compare");
2842 QString compareStrict("(function(a, b) { return a === b; })");
2843 QTest::newRow("true") << "true" << compareStrict;
2844 QTest::newRow("undefined") << "undefined" << compareStrict;
2845 QTest::newRow("null") << "null" << compareStrict;
2846 QTest::newRow("123") << "123" << compareStrict;
2847 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2849 QString comparePropertiesStrict(
2851 " if (typeof b != 'object')"
2853 " var props = Object.getOwnPropertyNames(b);"
2854 " for (var i = 0; i < props.length; ++i) {"
2855 " var p = props[i];"
2856 " return arguments.callee(a[p], b[p]);"
2859 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2860 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2863 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2865 QFETCH(QString, expression);
2866 QFETCH(QString, compare);
2868 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2869 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2870 QVERIFY(object != 0);
2872 QJSValue value = engine.evaluate(expression);
2873 QVERIFY(!engine.hasUncaughtException());
2874 object->setProperty("expression", expression);
2875 object->setProperty("compare", compare);
2876 object->setProperty("pass", false);
2878 emit object->signalWithVariant(QVariant::fromValue(value));
2879 QVERIFY(object->property("pass").toBool());
2882 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2884 signalWithJSValueInVariant_data();
2887 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2889 QFETCH(QString, expression);
2890 QFETCH(QString, compare);
2892 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2893 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2894 QVERIFY(object != 0);
2897 QJSValue value = engine2.evaluate(expression);
2898 QVERIFY(!engine2.hasUncaughtException());
2899 object->setProperty("expression", expression);
2900 object->setProperty("compare", compare);
2901 object->setProperty("pass", false);
2903 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2904 emit object->signalWithVariant(QVariant::fromValue(value));
2905 QVERIFY(!object->property("pass").toBool());
2908 void tst_qdeclarativeecmascript::moduleApi_data()
2910 QTest::addColumn<QUrl>("testfile");
2911 QTest::addColumn<QString>("errorMessage");
2912 QTest::addColumn<QStringList>("warningMessages");
2913 QTest::addColumn<QStringList>("readProperties");
2914 QTest::addColumn<QVariantList>("readExpectedValues");
2915 QTest::addColumn<QStringList>("writeProperties");
2916 QTest::addColumn<QVariantList>("writeValues");
2917 QTest::addColumn<QStringList>("readBackProperties");
2918 QTest::addColumn<QVariantList>("readBackExpectedValues");
2920 QTest::newRow("qobject, register + read + method")
2921 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2924 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2925 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2926 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2932 QTest::newRow("script, register + read")
2933 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2936 << (QStringList() << "scriptTest")
2937 << (QVariantList() << 13)
2943 QTest::newRow("qobject, caching + read")
2944 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2947 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2948 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2954 QTest::newRow("script, caching + read")
2955 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2958 << (QStringList() << "scriptTest")
2959 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2965 QTest::newRow("qobject, writing + readonly constraints")
2966 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2968 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2969 << (QStringList() << "readOnlyProperty" << "writableProperty")
2970 << (QVariantList() << 20 << 50)
2971 << (QStringList() << "firstProperty" << "writableProperty")
2972 << (QVariantList() << 30 << 30)
2973 << (QStringList() << "readOnlyProperty" << "writableProperty")
2974 << (QVariantList() << 20 << 30);
2976 QTest::newRow("script, writing + readonly constraints")
2977 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2979 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2980 << (QStringList() << "readBack" << "unchanged")
2981 << (QVariantList() << 13 << 42)
2982 << (QStringList() << "firstProperty" << "secondProperty")
2983 << (QVariantList() << 30 << 30)
2984 << (QStringList() << "readBack" << "unchanged")
2985 << (QVariantList() << 30 << 42);
2987 QTest::newRow("qobject module API enum values in JS")
2988 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2991 << (QStringList() << "enumValue" << "enumMethod")
2992 << (QVariantList() << 42 << 30)
2998 QTest::newRow("qobject, invalid major version fail")
2999 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3000 << QString("QDeclarativeComponent: Component is not ready")
3009 QTest::newRow("qobject, invalid minor version fail")
3010 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3011 << QString("QDeclarativeComponent: Component is not ready")
3021 void tst_qdeclarativeecmascript::moduleApi()
3023 QFETCH(QUrl, testfile);
3024 QFETCH(QString, errorMessage);
3025 QFETCH(QStringList, warningMessages);
3026 QFETCH(QStringList, readProperties);
3027 QFETCH(QVariantList, readExpectedValues);
3028 QFETCH(QStringList, writeProperties);
3029 QFETCH(QVariantList, writeValues);
3030 QFETCH(QStringList, readBackProperties);
3031 QFETCH(QVariantList, readBackExpectedValues);
3033 QDeclarativeComponent component(&engine, testfile);
3035 if (!errorMessage.isEmpty())
3036 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3038 if (warningMessages.size())
3039 foreach (const QString &warning, warningMessages)
3040 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3042 QObject *object = component.create();
3043 if (!errorMessage.isEmpty()) {
3044 QVERIFY(object == 0);
3046 QVERIFY(object != 0);
3047 for (int i = 0; i < readProperties.size(); ++i)
3048 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3049 for (int i = 0; i < writeProperties.size(); ++i)
3050 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3051 for (int i = 0; i < readBackProperties.size(); ++i)
3052 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3057 void tst_qdeclarativeecmascript::importScripts_data()
3059 QTest::addColumn<QUrl>("testfile");
3060 QTest::addColumn<QString>("errorMessage");
3061 QTest::addColumn<QStringList>("warningMessages");
3062 QTest::addColumn<QStringList>("propertyNames");
3063 QTest::addColumn<QVariantList>("propertyValues");
3065 QTest::newRow("basic functionality")
3066 << TEST_FILE("jsimport/testImport.qml")
3069 << (QStringList() << QLatin1String("importedScriptStringValue")
3070 << QLatin1String("importedScriptFunctionValue")
3071 << QLatin1String("importedModuleAttachedPropertyValue")
3072 << QLatin1String("importedModuleEnumValue"))
3073 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3078 QTest::newRow("import scoping")
3079 << TEST_FILE("jsimport/testImportScoping.qml")
3082 << (QStringList() << QLatin1String("componentError"))
3083 << (QVariantList() << QVariant(5));
3085 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3086 << TEST_FILE("jsimportfail/failOne.qml")
3088 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3089 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3090 << (QVariantList() << QVariant(QString()));
3092 QTest::newRow("javascript imports in an import should be private to the import scope")
3093 << TEST_FILE("jsimportfail/failTwo.qml")
3095 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3096 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3097 << (QVariantList() << QVariant(QString()));
3099 QTest::newRow("module imports in an import should be private to the import scope")
3100 << TEST_FILE("jsimportfail/failThree.qml")
3102 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3103 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3104 << (QVariantList() << QVariant(false));
3106 QTest::newRow("typenames in an import should be private to the import scope")
3107 << TEST_FILE("jsimportfail/failFour.qml")
3109 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3110 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3111 << (QVariantList() << QVariant(0));
3113 QTest::newRow("import with imports has it's own activation scope")
3114 << TEST_FILE("jsimportfail/failFive.qml")
3116 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3117 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3118 << (QStringList() << QLatin1String("componentError"))
3119 << (QVariantList() << QVariant(0));
3121 QTest::newRow("import pragma library script")
3122 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3125 << (QStringList() << QLatin1String("testValue"))
3126 << (QVariantList() << QVariant(31));
3128 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3129 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3132 << (QStringList() << QLatin1String("testValue"))
3133 << (QVariantList() << QVariant(0));
3135 QTest::newRow("import pragma library script which has an import")
3136 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3139 << (QStringList() << QLatin1String("testValue"))
3140 << (QVariantList() << QVariant(55));
3142 QTest::newRow("import pragma library script which has a pragma library import")
3143 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3146 << (QStringList() << QLatin1String("testValue"))
3147 << (QVariantList() << QVariant(18));
3150 void tst_qdeclarativeecmascript::importScripts()
3152 QFETCH(QUrl, testfile);
3153 QFETCH(QString, errorMessage);
3154 QFETCH(QStringList, warningMessages);
3155 QFETCH(QStringList, propertyNames);
3156 QFETCH(QVariantList, propertyValues);
3158 QDeclarativeComponent component(&engine, testfile);
3160 if (!errorMessage.isEmpty())
3161 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3163 if (warningMessages.size())
3164 foreach (const QString &warning, warningMessages)
3165 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3167 QObject *object = component.create();
3168 if (!errorMessage.isEmpty()) {
3169 QVERIFY(object == 0);
3171 QVERIFY(object != 0);
3172 for (int i = 0; i < propertyNames.size(); ++i)
3173 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3178 void tst_qdeclarativeecmascript::scarceResources()
3180 QPixmap origPixmap(100, 100);
3181 origPixmap.fill(Qt::blue);
3183 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3184 ScarceResourceObject *eo = 0;
3185 QObject *object = 0;
3187 // in the following three cases, the instance created from the component
3188 // has a property which is a copy of the scarce resource; hence, the
3189 // resource should NOT be detached prior to deletion of the object instance,
3190 // unless the resource is destroyed explicitly.
3191 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3192 object = component.create();
3193 QVERIFY(object != 0);
3194 QVERIFY(object->property("scarceResourceCopy").isValid());
3195 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3196 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3197 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3198 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3201 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3202 object = componentTwo.create();
3203 QVERIFY(object != 0);
3204 QVERIFY(object->property("scarceResourceCopy").isValid());
3205 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3206 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3207 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3208 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3211 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3212 object = componentThree.create();
3213 QVERIFY(object != 0);
3214 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
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()); // should have explicitly been released during the evaluation of the binding.
3220 // in the following three cases, no other copy should exist in memory,
3221 // and so it should be detached (unless explicitly preserved).
3222 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3223 object = componentFour.create();
3224 QVERIFY(object != 0);
3225 QVERIFY(object->property("scarceResourceTest").isValid());
3226 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3227 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3228 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3229 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3232 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3233 object = componentFive.create();
3234 QVERIFY(object != 0);
3235 QVERIFY(object->property("scarceResourceTest").isValid());
3236 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3237 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3238 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3239 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3242 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3243 object = componentSix.create();
3244 QVERIFY(object != 0);
3245 QVERIFY(object->property("scarceResourceTest").isValid());
3246 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3247 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3248 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3249 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3252 // test that scarce resources are handled correctly for imports
3253 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3254 object = componentSeven.create();
3255 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3256 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3259 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3260 object = componentEight.create();
3261 QVERIFY(object != 0);
3262 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3263 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3266 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3267 object = componentNine.create();
3268 QVERIFY(object != 0);
3269 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3270 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3271 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3272 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3273 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3274 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3277 // test that scarce resources are handled properly in signal invocation
3278 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3279 object = componentTen.create();
3280 QVERIFY(object != 0);
3281 QObject *srsc = object->findChild<QObject*>("srsc");
3283 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3284 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3285 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3286 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3287 QMetaObject::invokeMethod(srsc, "testSignal");
3288 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3289 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3290 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3291 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3292 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3293 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3294 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3295 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3296 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3297 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3300 // test that scarce resources are handled properly from js functions in qml files
3301 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3302 object = componentEleven.create();
3303 QVERIFY(object != 0);
3304 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3305 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3306 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3307 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3308 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3309 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3310 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3311 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3312 QMetaObject::invokeMethod(object, "releaseScarceResource");
3313 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3314 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3315 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3316 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3319 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3320 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3321 object = componentTwelve.create();
3322 QVERIFY(object != 0);
3323 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3324 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3325 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3326 QString srp_name = object->property("srp_name").toString();
3327 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3328 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3329 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3330 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3331 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3332 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3333 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3337 void tst_qdeclarativeecmascript::propertyChangeSlots()
3339 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3340 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3341 QObject *object = component.create();
3342 QVERIFY(object != 0);
3345 // ensure that invalid property names fail properly.
3346 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3347 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3348 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3349 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3350 object = e1.create();
3351 QVERIFY(object == 0);
3354 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3355 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3356 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3357 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3358 object = e2.create();
3359 QVERIFY(object == 0);
3362 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3363 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3364 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3365 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3366 object = e3.create();
3367 QVERIFY(object == 0);
3370 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3371 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3372 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3373 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3374 object = e4.create();
3375 QVERIFY(object == 0);
3379 void tst_qdeclarativeecmascript::propertyVar_data()
3381 QTest::addColumn<QUrl>("qmlFile");
3384 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3385 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3386 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3387 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3388 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3389 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3390 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3391 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3392 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3395 void tst_qdeclarativeecmascript::propertyVar()
3397 QFETCH(QUrl, qmlFile);
3399 QDeclarativeComponent component(&engine, qmlFile);
3400 QObject *object = component.create();
3401 QVERIFY(object != 0);
3403 QCOMPARE(object->property("test").toBool(), true);
3408 // Tests that we can write QVariant values to var properties from C++
3409 void tst_qdeclarativeecmascript::propertyVarCpp()
3411 QObject *object = 0;
3413 // ensure that writing to and reading from a var property from cpp works as required.
3414 // Literal values stored in var properties can be read and written as QVariants
3415 // of a specific type, whereas object values are read as QVariantMaps.
3416 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3417 object = component.create();
3418 QVERIFY(object != 0);
3419 // assign int to property var that currently has int assigned
3420 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3421 QCOMPARE(object->property("varBound"), QVariant(15));
3422 QCOMPARE(object->property("intBound"), QVariant(15));
3423 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3424 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3425 // assign string to property var that current has bool assigned
3426 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3427 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3428 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3429 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3430 // now enforce behaviour when accessing JavaScript objects from cpp.
3431 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3435 static void gc(QDeclarativeEngine &engine)
3437 engine.collectGarbage();
3438 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3441 void tst_qdeclarativeecmascript::propertyVarOwnership()
3443 // Referenced JS objects are not collected
3445 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3446 QObject *object = component.create();
3447 QVERIFY(object != 0);
3448 QCOMPARE(object->property("test").toBool(), false);
3449 QMetaObject::invokeMethod(object, "runTest");
3450 QCOMPARE(object->property("test").toBool(), true);
3453 // Referenced JS objects are not collected
3455 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3456 QObject *object = component.create();
3457 QVERIFY(object != 0);
3458 QCOMPARE(object->property("test").toBool(), false);
3459 QMetaObject::invokeMethod(object, "runTest");
3460 QCOMPARE(object->property("test").toBool(), true);
3463 // Qt objects are not collected until they've been dereferenced
3465 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3466 QObject *object = component.create();
3467 QVERIFY(object != 0);
3469 QCOMPARE(object->property("test2").toBool(), false);
3470 QCOMPARE(object->property("test2").toBool(), false);
3472 QMetaObject::invokeMethod(object, "runTest");
3473 QCOMPARE(object->property("test1").toBool(), true);
3475 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3476 QVERIFY(!referencedObject.isNull());
3478 QVERIFY(!referencedObject.isNull());
3480 QMetaObject::invokeMethod(object, "runTest2");
3481 QCOMPARE(object->property("test2").toBool(), true);
3483 QVERIFY(referencedObject.isNull());
3487 // Self reference does not prevent Qt object collection
3489 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3490 QObject *object = component.create();
3491 QVERIFY(object != 0);
3493 QCOMPARE(object->property("test").toBool(), true);
3495 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3496 QVERIFY(!referencedObject.isNull());
3498 QVERIFY(!referencedObject.isNull());
3500 QMetaObject::invokeMethod(object, "runTest");
3502 QVERIFY(referencedObject.isNull());
3508 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3510 // The childObject has a reference to a different QObject. We want to ensure
3511 // that the different item will not be cleaned up until required. IE, the childObject
3512 // has implicit ownership of the constructed QObject.
3513 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3514 QObject *object = component.create();
3515 QVERIFY(object != 0);
3516 QMetaObject::invokeMethod(object, "assignCircular");
3517 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3518 QObject *rootObject = object->property("vp").value<QObject*>();
3519 QVERIFY(rootObject != 0);
3520 QObject *childObject = rootObject->findChild<QObject*>("text");
3521 QVERIFY(childObject != 0);
3522 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3523 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3524 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3525 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3526 QVERIFY(!qobjectGuard.isNull());
3527 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3528 QVERIFY(!qobjectGuard.isNull());
3529 QMetaObject::invokeMethod(object, "deassignCircular");
3530 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3531 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3535 void tst_qdeclarativeecmascript::propertyVarReparent()
3537 // ensure that nothing breaks if we re-parent objects
3538 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3539 QObject *object = component.create();
3540 QVERIFY(object != 0);
3541 QMetaObject::invokeMethod(object, "assignVarProp");
3542 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3543 QObject *rect = object->property("vp").value<QObject*>();
3544 QObject *text = rect->findChild<QObject*>("textOne");
3545 QObject *text2 = rect->findChild<QObject*>("textTwo");
3546 QWeakPointer<QObject> rectGuard(rect);
3547 QWeakPointer<QObject> textGuard(text);
3548 QWeakPointer<QObject> text2Guard(text2);
3549 QVERIFY(!rectGuard.isNull());
3550 QVERIFY(!textGuard.isNull());
3551 QVERIFY(!text2Guard.isNull());
3552 QCOMPARE(text->property("textCanary").toInt(), 11);
3553 QCOMPARE(text2->property("textCanary").toInt(), 12);
3554 // now construct an image which we will reparent.
3555 QMetaObject::invokeMethod(text2, "constructQObject");
3556 QObject *image = text2->property("vp").value<QObject*>();
3557 QWeakPointer<QObject> imageGuard(image);
3558 QVERIFY(!imageGuard.isNull());
3559 QCOMPARE(image->property("imageCanary").toInt(), 13);
3560 // now reparent the "Image" object (currently, it has JS ownership)
3561 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3562 QMetaObject::invokeMethod(text2, "deassignVp");
3563 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3564 QCOMPARE(text->property("textCanary").toInt(), 11);
3565 QCOMPARE(text2->property("textCanary").toInt(), 22);
3566 QVERIFY(!imageGuard.isNull()); // should still be alive.
3567 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3568 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3569 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3570 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3574 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3576 // sometimes reparenting can cause problems
3577 // (eg, if the ctxt is collected, varproperties are no longer available)
3578 // this test ensures that no crash occurs in that situation.
3579 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3580 QObject *object = component.create();
3581 QVERIFY(object != 0);
3582 QMetaObject::invokeMethod(object, "assignVarProp");
3583 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3584 QObject *rect = object->property("vp").value<QObject*>();
3585 QObject *text = rect->findChild<QObject*>("textOne");
3586 QObject *text2 = rect->findChild<QObject*>("textTwo");
3587 QWeakPointer<QObject> rectGuard(rect);
3588 QWeakPointer<QObject> textGuard(text);
3589 QWeakPointer<QObject> text2Guard(text2);
3590 QVERIFY(!rectGuard.isNull());
3591 QVERIFY(!textGuard.isNull());
3592 QVERIFY(!text2Guard.isNull());
3593 QCOMPARE(text->property("textCanary").toInt(), 11);
3594 QCOMPARE(text2->property("textCanary").toInt(), 12);
3595 // now construct an image which we will reparent.
3596 QMetaObject::invokeMethod(text2, "constructQObject");
3597 QObject *image = text2->property("vp").value<QObject*>();
3598 QWeakPointer<QObject> imageGuard(image);
3599 QVERIFY(!imageGuard.isNull());
3600 QCOMPARE(image->property("imageCanary").toInt(), 13);
3601 // now reparent the "Image" object (currently, it has JS ownership)
3602 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3603 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3604 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3605 QVERIFY(!imageGuard.isNull()); // should still be alive.
3606 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3608 QVERIFY(imageGuard.isNull()); // should now be dead.
3611 void tst_qdeclarativeecmascript::propertyVarCircular()
3613 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3614 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3615 QObject *object = component.create();
3616 QVERIFY(object != 0);
3617 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3618 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3619 QCOMPARE(object->property("canaryInt"), QVariant(5));
3620 QVariant canaryResourceVariant = object->property("canaryResource");
3621 QVERIFY(canaryResourceVariant.isValid());
3622 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3623 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3624 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3625 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3626 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3627 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3628 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3629 QCOMPARE(object->property("canaryInt"), QVariant(2));
3630 QCOMPARE(object->property("canaryResource"), QVariant(1));
3631 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3635 void tst_qdeclarativeecmascript::propertyVarCircular2()
3637 // track deletion of JS-owned parent item with Cpp-owned child
3638 // where the child has a var property referencing its parent.
3639 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3640 QObject *object = component.create();
3641 QVERIFY(object != 0);
3642 QMetaObject::invokeMethod(object, "assignCircular");
3643 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3644 QObject *rootObject = object->property("vp").value<QObject*>();
3645 QVERIFY(rootObject != 0);
3646 QObject *childObject = rootObject->findChild<QObject*>("text");
3647 QVERIFY(childObject != 0);
3648 QWeakPointer<QObject> rootObjectTracker(rootObject);
3649 QVERIFY(!rootObjectTracker.isNull());
3650 QWeakPointer<QObject> childObjectTracker(childObject);
3651 QVERIFY(!childObjectTracker.isNull());
3653 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3654 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3655 QMetaObject::invokeMethod(object, "deassignCircular");
3656 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3657 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3658 QVERIFY(childObjectTracker.isNull()); // should have been collected
3662 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3664 *(int*)(parameter) += 1;
3665 qPersistentDispose(object);
3668 void tst_qdeclarativeecmascript::propertyVarInheritance()
3670 int propertyVarWeakRefCallbackCount = 0;
3672 // enforce behaviour regarding element inheritance - ensure handle disposal.
3673 // The particular component under test here has a chain of references.
3674 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3675 QObject *object = component.create();
3676 QVERIFY(object != 0);
3677 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3678 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3679 // we want to be able to track when the varProperties array of the last metaobject is disposed
3680 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3681 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*>();
3682 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3683 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3684 v8::Persistent<v8::Value> icoCanaryHandle;
3685 v8::Persistent<v8::Value> ccoCanaryHandle;
3688 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3689 // public function which can return us a handle to something in the varProperties array.
3690 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3691 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3692 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3693 // as the varproperties array of each vmemo still references the resource.
3694 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3695 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3697 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3699 // now we deassign the var prop, which should trigger collection of item subtrees.
3700 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3701 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3702 // ensure that there are only weak handles to the underlying varProperties array remaining.
3704 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3706 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3707 // to what remains are weak, all varProperties arrays must have been collected.
3710 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3712 int propertyVarWeakRefCallbackCount = 0;
3714 // The particular component under test here does NOT have a chain of references; the
3715 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3716 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3717 QObject *object = component.create();
3718 QVERIFY(object != 0);
3719 QMetaObject::invokeMethod(object, "assignCircular");
3720 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3721 QObject *rootObject = object->property("vp").value<QObject*>();
3722 QVERIFY(rootObject != 0);
3723 QObject *childObject = rootObject->findChild<QObject*>("text");
3724 QVERIFY(childObject != 0);
3725 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3726 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3727 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3730 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3731 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3732 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3734 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3735 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3737 QMetaObject::invokeMethod(object, "deassignCircular");
3738 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3739 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3743 // Ensure that QObject type conversion works on binding assignment
3744 void tst_qdeclarativeecmascript::elementAssign()
3746 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3748 QObject *object = component.create();
3749 QVERIFY(object != 0);
3751 QCOMPARE(object->property("test").toBool(), true);
3757 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3759 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3761 QObject *object = component.create();
3762 QVERIFY(object != 0);
3764 QCOMPARE(object->property("test").toBool(), true);
3770 void tst_qdeclarativeecmascript::objectConversion()
3772 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3774 QObject *object = component.create();
3775 QVERIFY(object != 0);
3777 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3778 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3785 void tst_qdeclarativeecmascript::booleanConversion()
3787 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3789 QObject *object = component.create();
3790 QVERIFY(object != 0);
3792 QCOMPARE(object->property("test_true1").toBool(), true);
3793 QCOMPARE(object->property("test_true2").toBool(), true);
3794 QCOMPARE(object->property("test_true3").toBool(), true);
3795 QCOMPARE(object->property("test_true4").toBool(), true);
3796 QCOMPARE(object->property("test_true5").toBool(), true);
3798 QCOMPARE(object->property("test_false1").toBool(), false);
3799 QCOMPARE(object->property("test_false2").toBool(), false);
3800 QCOMPARE(object->property("test_false3").toBool(), false);
3805 void tst_qdeclarativeecmascript::handleReferenceManagement()
3810 // Linear QObject reference
3811 QDeclarativeEngine hrmEngine;
3812 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3813 QObject *object = component.create();
3814 QVERIFY(object != 0);
3815 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3816 cro->setDtorCount(&dtorCount);
3817 QMetaObject::invokeMethod(object, "createReference");
3819 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3821 hrmEngine.collectGarbage();
3822 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3823 QCOMPARE(dtorCount, 3);
3828 // Circular QObject reference
3829 QDeclarativeEngine hrmEngine;
3830 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3831 QObject *object = component.create();
3832 QVERIFY(object != 0);
3833 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3834 cro->setDtorCount(&dtorCount);
3835 QMetaObject::invokeMethod(object, "circularReference");
3837 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3839 hrmEngine.collectGarbage();
3840 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3841 QCOMPARE(dtorCount, 3);
3846 // Linear handle reference
3847 QDeclarativeEngine hrmEngine;
3848 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3849 QObject *object = component.create();
3850 QVERIFY(object != 0);
3851 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3853 crh->setDtorCount(&dtorCount);
3854 QMetaObject::invokeMethod(object, "createReference");
3855 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3856 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3857 QVERIFY(first != 0);
3858 QVERIFY(second != 0);
3859 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3860 // now we have to reparent second and make second owned by JS.
3861 second->setParent(0);
3862 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3864 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3866 hrmEngine.collectGarbage();
3867 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3868 QCOMPARE(dtorCount, 3);
3873 // Circular handle reference
3874 QDeclarativeEngine hrmEngine;
3875 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3876 QObject *object = component.create();
3877 QVERIFY(object != 0);
3878 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3880 crh->setDtorCount(&dtorCount);
3881 QMetaObject::invokeMethod(object, "circularReference");
3882 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3883 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3884 QVERIFY(first != 0);
3885 QVERIFY(second != 0);
3886 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3887 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3888 // now we have to reparent and change ownership.
3889 first->setParent(0);
3890 second->setParent(0);
3891 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3892 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3894 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3896 hrmEngine.collectGarbage();
3897 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3898 QCOMPARE(dtorCount, 3);
3903 // multiple engine interaction - linear reference
3904 QDeclarativeEngine hrmEngine1;
3905 QDeclarativeEngine hrmEngine2;
3906 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3907 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3908 QObject *object1 = component1.create();
3909 QObject *object2 = component2.create();
3910 QVERIFY(object1 != 0);
3911 QVERIFY(object2 != 0);
3912 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3913 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3916 crh1->setDtorCount(&dtorCount);
3917 crh2->setDtorCount(&dtorCount);
3918 QMetaObject::invokeMethod(object1, "createReference");
3919 QMetaObject::invokeMethod(object2, "createReference");
3920 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3921 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3922 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3923 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3924 QVERIFY(first1 != 0);
3925 QVERIFY(second1 != 0);
3926 QVERIFY(first2 != 0);
3927 QVERIFY(second2 != 0);
3928 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3929 // now we have to reparent second2 and make second2 owned by JS.
3930 second2->setParent(0);
3931 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3933 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3934 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3937 hrmEngine1.collectGarbage();
3938 hrmEngine2.collectGarbage();
3939 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3940 QCOMPARE(dtorCount, 6);
3945 // multiple engine interaction - circular reference
3946 QDeclarativeEngine hrmEngine1;
3947 QDeclarativeEngine hrmEngine2;
3948 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3949 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3950 QObject *object1 = component1.create();
3951 QObject *object2 = component2.create();
3952 QVERIFY(object1 != 0);
3953 QVERIFY(object2 != 0);
3954 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3955 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3958 crh1->setDtorCount(&dtorCount);
3959 crh2->setDtorCount(&dtorCount);
3960 QMetaObject::invokeMethod(object1, "createReference");
3961 QMetaObject::invokeMethod(object2, "createReference");
3962 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3963 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3964 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3965 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3966 QVERIFY(first1 != 0);
3967 QVERIFY(second1 != 0);
3968 QVERIFY(first2 != 0);
3969 QVERIFY(second2 != 0);
3970 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3971 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3972 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3973 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3974 // now we have to reparent and change ownership to JS.
3975 first1->setParent(0);
3976 second1->setParent(0);
3977 first2->setParent(0);
3978 second2->setParent(0);
3979 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3980 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3981 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3982 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3984 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3985 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3988 hrmEngine1.collectGarbage();
3989 hrmEngine2.collectGarbage();
3990 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3991 QCOMPARE(dtorCount, 6);
3996 // multiple engine interaction - linear reference with engine deletion
3997 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3998 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3999 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4000 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4001 QObject *object1 = component1.create();
4002 QObject *object2 = component2.create();
4003 QVERIFY(object1 != 0);
4004 QVERIFY(object2 != 0);
4005 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4006 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4009 crh1->setDtorCount(&dtorCount);
4010 crh2->setDtorCount(&dtorCount);
4011 QMetaObject::invokeMethod(object1, "createReference");
4012 QMetaObject::invokeMethod(object2, "createReference");
4013 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4014 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4015 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4016 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4017 QVERIFY(first1 != 0);
4018 QVERIFY(second1 != 0);
4019 QVERIFY(first2 != 0);
4020 QVERIFY(second2 != 0);
4021 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4022 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4023 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4024 // now we have to reparent and change ownership to JS.
4025 first1->setParent(crh1);
4026 second1->setParent(0);
4027 first2->setParent(0);
4028 second2->setParent(0);
4029 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4030 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4031 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4033 QCOMPARE(dtorCount, 0);
4036 QCOMPARE(dtorCount, 0);
4039 hrmEngine1->collectGarbage();
4040 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4041 QCOMPARE(dtorCount, 6);
4046 void tst_qdeclarativeecmascript::stringArg()
4048 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4049 QObject *object = component.create();
4050 QVERIFY(object != 0);
4051 QMetaObject::invokeMethod(object, "success");
4052 QVERIFY(object->property("returnValue").toBool());
4054 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4055 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4056 QMetaObject::invokeMethod(object, "failure");
4057 QVERIFY(object->property("returnValue").toBool());
4062 void tst_qdeclarativeecmascript::readonlyDeclaration()
4064 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4066 QObject *object = component.create();
4067 QVERIFY(object != 0);
4069 QCOMPARE(object->property("test").toBool(), true);
4074 Q_DECLARE_METATYPE(QList<int>)
4075 Q_DECLARE_METATYPE(QList<qreal>)
4076 Q_DECLARE_METATYPE(QList<bool>)
4077 Q_DECLARE_METATYPE(QList<QString>)
4078 Q_DECLARE_METATYPE(QList<QUrl>)
4079 void tst_qdeclarativeecmascript::sequenceConversionRead()
4082 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4083 QDeclarativeComponent component(&engine, qmlFile);
4084 QObject *object = component.create();
4085 QVERIFY(object != 0);
4086 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4089 QMetaObject::invokeMethod(object, "readSequences");
4090 QList<int> intList; intList << 1 << 2 << 3 << 4;
4091 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4092 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4093 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4094 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4095 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4096 QList<bool> boolList; boolList << true << false << true << false;
4097 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4098 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4099 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4100 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4101 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4102 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4103 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4104 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4105 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4106 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4107 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4109 QMetaObject::invokeMethod(object, "readSequenceElements");
4110 QCOMPARE(object->property("intVal").toInt(), 2);
4111 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4112 QCOMPARE(object->property("boolVal").toBool(), false);
4113 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4114 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4115 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4117 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4118 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4120 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4121 QDeclarativeProperty seqProp(seq, "intListProperty");
4122 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4123 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4124 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4126 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4127 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4133 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4134 QDeclarativeComponent component(&engine, qmlFile);
4135 QObject *object = component.create();
4136 QVERIFY(object != 0);
4137 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4140 // we haven't registered QList<QPoint> as a sequence type.
4141 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4142 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4143 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4144 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4146 QMetaObject::invokeMethod(object, "performTest");
4148 // QList<QPoint> has not been registered as a sequence type.
4149 QCOMPARE(object->property("pointListLength").toInt(), 0);
4150 QVERIFY(!object->property("pointList").isValid());
4151 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4152 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4153 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4159 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4162 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4163 QDeclarativeComponent component(&engine, qmlFile);
4164 QObject *object = component.create();
4165 QVERIFY(object != 0);
4166 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4169 QMetaObject::invokeMethod(object, "writeSequences");
4170 QCOMPARE(object->property("success").toBool(), true);
4172 QMetaObject::invokeMethod(object, "writeSequenceElements");
4173 QCOMPARE(object->property("success").toBool(), true);
4175 QMetaObject::invokeMethod(object, "writeOtherElements");
4176 QCOMPARE(object->property("success").toBool(), true);
4178 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4179 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4185 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4186 QDeclarativeComponent component(&engine, qmlFile);
4187 QObject *object = component.create();
4188 QVERIFY(object != 0);
4189 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4192 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4193 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4194 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4196 QMetaObject::invokeMethod(object, "performTest");
4198 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4199 QCOMPARE(seq->pointListProperty(), pointList);
4205 void tst_qdeclarativeecmascript::sequenceConversionArray()
4207 // ensure that in JS the returned sequences act just like normal JS Arrays.
4208 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4209 QDeclarativeComponent component(&engine, qmlFile);
4210 QObject *object = component.create();
4211 QVERIFY(object != 0);
4212 //QMetaObject::invokeMethod(object, "indexedAccess");
4213 //QVERIFY(object->property("success").toBool());
4214 //QMetaObject::invokeMethod(object, "arrayOperations");
4215 //QVERIFY(object->property("success").toBool());
4216 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4217 QVERIFY(object->property("success").toBool());
4218 //QMetaObject::invokeMethod(object, "testReferenceDeletion");
4219 //QCOMPARE(object->property("referenceDeletion").toBool(), true);
4223 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4225 // ensure that sequence conversion operations work correctly in a worker thread
4226 // and that serialisation between the main and worker thread succeeds.
4227 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4228 QDeclarativeComponent component(&engine, qmlFile);
4229 QObject *object = component.create();
4230 QVERIFY(object != 0);
4232 QMetaObject::invokeMethod(object, "testIntSequence");
4233 QTRY_VERIFY(object->property("finished").toBool());
4234 QVERIFY(object->property("success").toBool());
4236 QMetaObject::invokeMethod(object, "testQrealSequence");
4237 QTRY_VERIFY(object->property("finished").toBool());
4238 QVERIFY(object->property("success").toBool());
4240 QMetaObject::invokeMethod(object, "testBoolSequence");
4241 QTRY_VERIFY(object->property("finished").toBool());
4242 QVERIFY(object->property("success").toBool());
4244 QMetaObject::invokeMethod(object, "testStringSequence");
4245 QTRY_VERIFY(object->property("finished").toBool());
4246 QVERIFY(object->property("success").toBool());
4248 QMetaObject::invokeMethod(object, "testQStringSequence");
4249 QTRY_VERIFY(object->property("finished").toBool());
4250 QVERIFY(object->property("success").toBool());
4252 QMetaObject::invokeMethod(object, "testUrlSequence");
4253 QTRY_VERIFY(object->property("finished").toBool());
4254 QVERIFY(object->property("success").toBool());
4256 QMetaObject::invokeMethod(object, "testVariantSequence");
4257 QTRY_VERIFY(object->property("finished").toBool());
4258 QVERIFY(object->property("success").toBool());
4263 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4266 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4267 QDeclarativeComponent component(&engine, qmlFile);
4268 QObject *object = component.create();
4269 QVERIFY(object != 0);
4270 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4271 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4272 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4273 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4274 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4279 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4280 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4281 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4282 QDeclarativeComponent component(&engine, qmlFile);
4283 QObject *object = component.create();
4284 QVERIFY(object != 0);
4289 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4291 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4292 QDeclarativeComponent component(&engine, qmlFile);
4293 QObject *object = component.create();
4294 QVERIFY(object != 0);
4295 QMetaObject::invokeMethod(object, "testCopySequences");
4296 QCOMPARE(object->property("success").toBool(), true);
4297 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4298 QCOMPARE(object->property("success").toBool(), true);
4299 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4300 QCOMPARE(object->property("success").toBool(), true);
4304 // Test that assigning a null object works
4305 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4306 void tst_qdeclarativeecmascript::nullObjectBinding()
4308 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4310 QObject *object = component.create();
4311 QVERIFY(object != 0);
4313 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4318 // Test that bindings don't evaluate once the engine has been destroyed
4319 void tst_qdeclarativeecmascript::deletedEngine()
4321 QDeclarativeEngine *engine = new QDeclarativeEngine;
4322 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4324 QObject *object = component.create();
4325 QVERIFY(object != 0);
4327 QCOMPARE(object->property("a").toInt(), 39);
4328 object->setProperty("b", QVariant(9));
4329 QCOMPARE(object->property("a").toInt(), 117);
4333 QCOMPARE(object->property("a").toInt(), 117);
4334 object->setProperty("b", QVariant(10));
4335 QCOMPARE(object->property("a").toInt(), 117);
4340 // Test the crashing part of QTBUG-9705
4341 void tst_qdeclarativeecmascript::libraryScriptAssert()
4343 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4345 QObject *object = component.create();
4346 QVERIFY(object != 0);
4351 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4353 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4355 QObject *object = component.create();
4356 QVERIFY(object != 0);
4358 QCOMPARE(object->property("test1").toInt(), 10);
4359 QCOMPARE(object->property("test2").toInt(), 11);
4361 object->setProperty("runTest", true);
4363 QCOMPARE(object->property("test1"), QVariant());
4364 QCOMPARE(object->property("test2"), QVariant());
4370 void tst_qdeclarativeecmascript::qtbug_9792()
4372 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4374 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4376 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4377 QVERIFY(object != 0);
4379 QString message = QString(QLatin1String("Hello world! (%1:%2)")).arg(TEST_FILE("qtbug_9792.qml").toString()).arg(4);
4380 QTest::ignoreMessage(QtDebugMsg, qPrintable(message));
4381 object->basicSignal();
4385 transientErrorsMsgCount = 0;
4386 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4388 object->basicSignal();
4390 qInstallMsgHandler(old);
4392 QCOMPARE(transientErrorsMsgCount, 0);
4397 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4398 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4400 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4402 QObject *o = component.create();
4405 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4406 QVERIFY(nested != 0);
4408 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4411 nested = qvariant_cast<QObject *>(o->property("object"));
4412 QVERIFY(nested == 0);
4414 // If the bug is present, the next line will crash
4418 // Test that we shut down without stupid warnings
4419 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4422 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4424 QObject *o = component.create();
4426 transientErrorsMsgCount = 0;
4427 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4431 qInstallMsgHandler(old);
4433 QCOMPARE(transientErrorsMsgCount, 0);
4438 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4440 QObject *o = component.create();
4442 transientErrorsMsgCount = 0;
4443 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4447 qInstallMsgHandler(old);
4449 QCOMPARE(transientErrorsMsgCount, 0);
4453 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4456 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4458 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4461 QVERIFY(o->objectProperty() != 0);
4463 o->setProperty("runTest", true);
4465 QVERIFY(o->objectProperty() == 0);
4471 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4473 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4476 QVERIFY(o->objectProperty() == 0);
4482 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4484 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4486 QString url = component.url().toString();
4487 QString warning = url + ":4: Unable to assign a function to a property.";
4488 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4490 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4493 QVERIFY(!o->property("a").isValid());
4498 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4500 QFETCH(QString, triggerProperty);
4502 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4503 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4505 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4507 QVERIFY(!o->property("a").isValid());
4509 o->setProperty("aNumber", QVariant(5));
4510 o->setProperty(triggerProperty.toUtf8().constData(), true);
4511 QCOMPARE(o->property("a"), QVariant(50));
4513 o->setProperty("aNumber", QVariant(10));
4514 QCOMPARE(o->property("a"), QVariant(100));
4519 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4521 QTest::addColumn<QString>("triggerProperty");
4523 QTest::newRow("assign to property") << "assignToProperty";
4524 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4526 QTest::newRow("assign to value type") << "assignToValueType";
4528 QTest::newRow("use 'this'") << "assignWithThis";
4529 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4532 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4534 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4535 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4537 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4539 QVERIFY(!o->property("a").isValid());
4541 o->setProperty("assignFuncWithoutReturn", true);
4542 QVERIFY(!o->property("a").isValid());
4544 QString url = component.url().toString();
4545 QString warning = url + ":67: Unable to assign QString to int";
4546 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4547 o->setProperty("assignWrongType", true);
4549 warning = url + ":71: Unable to assign QString to int";
4550 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4551 o->setProperty("assignWrongTypeToValueType", true);
4556 void tst_qdeclarativeecmascript::eval()
4558 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4560 QObject *o = component.create();
4563 QCOMPARE(o->property("test1").toBool(), true);
4564 QCOMPARE(o->property("test2").toBool(), true);
4565 QCOMPARE(o->property("test3").toBool(), true);
4566 QCOMPARE(o->property("test4").toBool(), true);
4567 QCOMPARE(o->property("test5").toBool(), true);
4572 void tst_qdeclarativeecmascript::function()
4574 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4576 QObject *o = component.create();
4579 QCOMPARE(o->property("test1").toBool(), true);
4580 QCOMPARE(o->property("test2").toBool(), true);
4581 QCOMPARE(o->property("test3").toBool(), true);
4586 // Test the "Qt.include" method
4587 void tst_qdeclarativeecmascript::include()
4589 // Non-library relative include
4591 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4592 QObject *o = component.create();
4595 QCOMPARE(o->property("test0").toInt(), 99);
4596 QCOMPARE(o->property("test1").toBool(), true);
4597 QCOMPARE(o->property("test2").toBool(), true);
4598 QCOMPARE(o->property("test2_1").toBool(), true);
4599 QCOMPARE(o->property("test3").toBool(), true);
4600 QCOMPARE(o->property("test3_1").toBool(), true);
4605 // Library relative include
4607 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4608 QObject *o = component.create();
4611 QCOMPARE(o->property("test0").toInt(), 99);
4612 QCOMPARE(o->property("test1").toBool(), true);
4613 QCOMPARE(o->property("test2").toBool(), true);
4614 QCOMPARE(o->property("test2_1").toBool(), true);
4615 QCOMPARE(o->property("test3").toBool(), true);
4616 QCOMPARE(o->property("test3_1").toBool(), true);
4623 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4624 QObject *o = component.create();
4627 QCOMPARE(o->property("test1").toBool(), true);
4628 QCOMPARE(o->property("test2").toBool(), true);
4629 QCOMPARE(o->property("test3").toBool(), true);
4630 QCOMPARE(o->property("test4").toBool(), true);
4631 QCOMPARE(o->property("test5").toBool(), true);
4632 QCOMPARE(o->property("test6").toBool(), true);
4637 // Including file with ".pragma library"
4639 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4640 QObject *o = component.create();
4642 QCOMPARE(o->property("test1").toInt(), 100);
4649 TestHTTPServer server(8111);
4650 QVERIFY(server.isValid());
4651 server.serveDirectory(TESTDATA(""));
4653 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4654 QObject *o = component.create();
4657 QTRY_VERIFY(o->property("done").toBool() == true);
4658 QTRY_VERIFY(o->property("done2").toBool() == true);
4660 QCOMPARE(o->property("test1").toBool(), true);
4661 QCOMPARE(o->property("test2").toBool(), true);
4662 QCOMPARE(o->property("test3").toBool(), true);
4663 QCOMPARE(o->property("test4").toBool(), true);
4664 QCOMPARE(o->property("test5").toBool(), true);
4666 QCOMPARE(o->property("test6").toBool(), true);
4667 QCOMPARE(o->property("test7").toBool(), true);
4668 QCOMPARE(o->property("test8").toBool(), true);
4669 QCOMPARE(o->property("test9").toBool(), true);
4670 QCOMPARE(o->property("test10").toBool(), true);
4677 TestHTTPServer server(8111);
4678 QVERIFY(server.isValid());
4679 server.serveDirectory(TESTDATA(""));
4681 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4682 QObject *o = component.create();
4685 QTRY_VERIFY(o->property("done").toBool() == true);
4687 QCOMPARE(o->property("test1").toBool(), true);
4688 QCOMPARE(o->property("test2").toBool(), true);
4689 QCOMPARE(o->property("test3").toBool(), true);
4695 void tst_qdeclarativeecmascript::signalHandlers()
4697 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4698 QObject *o = component.create();
4701 QVERIFY(o->property("count").toInt() == 0);
4702 QMetaObject::invokeMethod(o, "testSignalCall");
4703 QCOMPARE(o->property("count").toInt(), 1);
4705 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4706 QCOMPARE(o->property("count").toInt(), 1);
4707 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4709 QVERIFY(o->property("funcCount").toInt() == 0);
4710 QMetaObject::invokeMethod(o, "testSignalConnection");
4711 QCOMPARE(o->property("funcCount").toInt(), 1);
4713 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4714 QCOMPARE(o->property("funcCount").toInt(), 2);
4716 QMetaObject::invokeMethod(o, "testSignalDefined");
4717 QCOMPARE(o->property("definedResult").toBool(), true);
4719 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4720 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4725 void tst_qdeclarativeecmascript::qtbug_10696()
4727 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4728 QObject *o = component.create();
4733 void tst_qdeclarativeecmascript::qtbug_11606()
4735 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4736 QObject *o = component.create();
4738 QCOMPARE(o->property("test").toBool(), true);
4742 void tst_qdeclarativeecmascript::qtbug_11600()
4744 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4745 QObject *o = component.create();
4747 QCOMPARE(o->property("test").toBool(), true);
4751 // Reading and writing non-scriptable properties should fail
4752 void tst_qdeclarativeecmascript::nonscriptable()
4754 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4755 QObject *o = component.create();
4757 QCOMPARE(o->property("readOk").toBool(), true);
4758 QCOMPARE(o->property("writeOk").toBool(), true);
4762 // deleteLater() should not be callable from QML
4763 void tst_qdeclarativeecmascript::deleteLater()
4765 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4766 QObject *o = component.create();
4768 QCOMPARE(o->property("test").toBool(), true);
4772 void tst_qdeclarativeecmascript::in()
4774 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4775 QObject *o = component.create();
4777 QCOMPARE(o->property("test1").toBool(), true);
4778 QCOMPARE(o->property("test2").toBool(), true);
4782 void tst_qdeclarativeecmascript::typeOf()
4784 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4785 QObject *o = component.create();
4787 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4788 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4789 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4790 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4791 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4792 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4793 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4794 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4795 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4796 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4801 void tst_qdeclarativeecmascript::sharedAttachedObject()
4803 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4804 QObject *o = component.create();
4806 QCOMPARE(o->property("test1").toBool(), true);
4807 QCOMPARE(o->property("test2").toBool(), true);
4812 void tst_qdeclarativeecmascript::objectName()
4814 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4815 QObject *o = component.create();
4818 QCOMPARE(o->property("test1").toString(), QString("hello"));
4819 QCOMPARE(o->property("test2").toString(), QString("ell"));
4821 o->setObjectName("world");
4823 QCOMPARE(o->property("test1").toString(), QString("world"));
4824 QCOMPARE(o->property("test2").toString(), QString("orl"));
4829 void tst_qdeclarativeecmascript::writeRemovesBinding()
4831 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4832 QObject *o = component.create();
4835 QCOMPARE(o->property("test").toBool(), true);
4840 // Test bindings assigned to alias properties actually assign to the alias' target
4841 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4843 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4844 QObject *o = component.create();
4847 QCOMPARE(o->property("test").toBool(), true);
4852 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4853 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4856 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4857 QObject *o = component.create();
4860 QCOMPARE(o->property("test").toBool(), true);
4866 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4867 QObject *o = component.create();
4870 QCOMPARE(o->property("test").toBool(), true);
4876 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4877 QObject *o = component.create();
4880 QCOMPARE(o->property("test").toBool(), true);
4886 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4887 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4890 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4891 QObject *o = component.create();
4894 QCOMPARE(o->property("test").toBool(), true);
4900 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4901 QObject *o = component.create();
4904 QCOMPARE(o->property("test").toBool(), true);
4910 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4911 QObject *o = component.create();
4914 QCOMPARE(o->property("test").toBool(), true);
4920 // Allow an alais to a composite element
4922 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4924 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4926 QObject *object = component.create();
4927 QVERIFY(object != 0);
4932 void tst_qdeclarativeecmascript::qtbug_20344()
4934 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
4936 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
4937 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
4939 QObject *object = component.create();
4940 QVERIFY(object != 0);
4945 void tst_qdeclarativeecmascript::revisionErrors()
4948 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4949 QString url = component.url().toString();
4951 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4952 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4953 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4955 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4956 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4957 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4958 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4959 QVERIFY(object != 0);
4963 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4964 QString url = component.url().toString();
4966 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4967 // method2, prop2 from MyRevisionedClass not available
4968 // method4, prop4 from MyRevisionedSubclass not available
4969 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4970 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4971 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4972 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4973 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4975 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4976 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4977 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4978 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4979 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4980 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4981 QVERIFY(object != 0);
4985 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4986 QString url = component.url().toString();
4988 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4989 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4990 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4991 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4992 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4993 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4994 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4995 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4996 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4997 QVERIFY(object != 0);
5002 void tst_qdeclarativeecmascript::revision()
5005 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5006 QString url = component.url().toString();
5008 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5009 QVERIFY(object != 0);
5013 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5014 QString url = component.url().toString();
5016 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5017 QVERIFY(object != 0);
5021 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5022 QString url = component.url().toString();
5024 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5025 QVERIFY(object != 0);
5028 // Test that non-root classes can resolve revisioned methods
5030 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5032 QObject *object = component.create();
5033 QVERIFY(object != 0);
5034 QCOMPARE(object->property("test").toReal(), 11.);
5039 void tst_qdeclarativeecmascript::realToInt()
5041 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5042 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5043 QVERIFY(object != 0);
5045 QMetaObject::invokeMethod(object, "test1");
5046 QCOMPARE(object->value(), int(4));
5047 QMetaObject::invokeMethod(object, "test2");
5048 QCOMPARE(object->value(), int(8));
5050 void tst_qdeclarativeecmascript::dynamicString()
5052 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5053 QObject *object = component.create();
5054 QVERIFY(object != 0);
5055 QCOMPARE(object->property("stringProperty").toString(),
5056 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5059 void tst_qdeclarativeecmascript::automaticSemicolon()
5061 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5062 QObject *object = component.create();
5063 QVERIFY(object != 0);
5066 void tst_qdeclarativeecmascript::unaryExpression()
5068 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5069 QObject *object = component.create();
5070 QVERIFY(object != 0);
5073 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5074 void tst_qdeclarativeecmascript::doubleEvaluate()
5076 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5077 QObject *object = component.create();
5078 QVERIFY(object != 0);
5079 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5081 QCOMPARE(wc->count(), 1);
5083 wc->setProperty("x", 9);
5085 QCOMPARE(wc->count(), 2);
5090 static QStringList messages;
5091 static void captureMsgHandler(QtMsgType, const char *msg)
5093 messages.append(QLatin1String(msg));
5096 void tst_qdeclarativeecmascript::nonNotifyable()
5098 QV4Compiler::enableV4(false);
5099 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5100 QV4Compiler::enableV4(true);
5102 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5104 QObject *object = component.create();
5105 qInstallMsgHandler(old);
5107 QVERIFY(object != 0);
5109 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5110 component.url().toString() +
5111 QLatin1String(":5 depends on non-NOTIFYable properties:");
5112 QString expected2 = QLatin1String(" ") +
5113 QLatin1String(object->metaObject()->className()) +
5114 QLatin1String("::value");
5116 QCOMPARE(messages.length(), 2);
5117 QCOMPARE(messages.at(0), expected1);
5118 QCOMPARE(messages.at(1), expected2);
5123 void tst_qdeclarativeecmascript::forInLoop()
5125 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5126 QObject *object = component.create();
5127 QVERIFY(object != 0);
5129 QMetaObject::invokeMethod(object, "listProperty");
5131 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5132 QCOMPARE(r.size(), 3);
5133 QCOMPARE(r[0],QLatin1String("0=obj1"));
5134 QCOMPARE(r[1],QLatin1String("1=obj2"));
5135 QCOMPARE(r[2],QLatin1String("2=obj3"));
5137 //TODO: should test for in loop for other objects (such as QObjects) as well.
5142 // An object the binding depends on is deleted while the binding is still running
5143 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5145 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5146 QObject *object = component.create();
5147 QVERIFY(object != 0);
5151 QTEST_MAIN(tst_qdeclarativeecmascript)
5153 #include "tst_qdeclarativeecmascript.moc"