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();
232 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
233 QDeclarativeEngine engine;
236 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
238 void tst_qdeclarativeecmascript::assignBasicTypes()
241 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
242 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
243 QVERIFY(object != 0);
244 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
245 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
246 QCOMPARE(object->stringProperty(), QString("Hello World!"));
247 QCOMPARE(object->uintProperty(), uint(10));
248 QCOMPARE(object->intProperty(), -19);
249 QCOMPARE((float)object->realProperty(), float(23.2));
250 QCOMPARE((float)object->doubleProperty(), float(-19.75));
251 QCOMPARE((float)object->floatProperty(), float(8.5));
252 QCOMPARE(object->colorProperty(), QColor("red"));
253 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
254 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
255 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
256 QCOMPARE(object->pointProperty(), QPoint(99,13));
257 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
258 QCOMPARE(object->sizeProperty(), QSize(99, 13));
259 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
260 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
261 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
262 QCOMPARE(object->boolProperty(), true);
263 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
264 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
265 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
269 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
270 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
271 QVERIFY(object != 0);
272 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
273 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
274 QCOMPARE(object->stringProperty(), QString("Hello World!"));
275 QCOMPARE(object->uintProperty(), uint(10));
276 QCOMPARE(object->intProperty(), -19);
277 QCOMPARE((float)object->realProperty(), float(23.2));
278 QCOMPARE((float)object->doubleProperty(), float(-19.75));
279 QCOMPARE((float)object->floatProperty(), float(8.5));
280 QCOMPARE(object->colorProperty(), QColor("red"));
281 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
282 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
283 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
284 QCOMPARE(object->pointProperty(), QPoint(99,13));
285 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
286 QCOMPARE(object->sizeProperty(), QSize(99, 13));
287 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
288 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
289 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
290 QCOMPARE(object->boolProperty(), true);
291 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
292 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
293 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
298 void tst_qdeclarativeecmascript::idShortcutInvalidates()
301 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
302 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
303 QVERIFY(object != 0);
304 QVERIFY(object->objectProperty() != 0);
305 delete object->objectProperty();
306 QVERIFY(object->objectProperty() == 0);
311 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
312 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
313 QVERIFY(object != 0);
314 QVERIFY(object->objectProperty() != 0);
315 delete object->objectProperty();
316 QVERIFY(object->objectProperty() == 0);
321 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
324 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
325 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
326 QVERIFY(object != 0);
327 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
331 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
332 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
333 QVERIFY(object != 0);
334 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
339 void tst_qdeclarativeecmascript::signalAssignment()
342 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
343 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
344 QVERIFY(object != 0);
345 QCOMPARE(object->string(), QString());
346 emit object->basicSignal();
347 QCOMPARE(object->string(), QString("pass"));
352 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
353 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
354 QVERIFY(object != 0);
355 QCOMPARE(object->string(), QString());
356 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
357 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
362 void tst_qdeclarativeecmascript::methods()
365 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
366 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
367 QVERIFY(object != 0);
368 QCOMPARE(object->methodCalled(), false);
369 QCOMPARE(object->methodIntCalled(), false);
370 emit object->basicSignal();
371 QCOMPARE(object->methodCalled(), true);
372 QCOMPARE(object->methodIntCalled(), false);
377 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
378 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
379 QVERIFY(object != 0);
380 QCOMPARE(object->methodCalled(), false);
381 QCOMPARE(object->methodIntCalled(), false);
382 emit object->basicSignal();
383 QCOMPARE(object->methodCalled(), false);
384 QCOMPARE(object->methodIntCalled(), true);
389 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
390 QObject *object = component.create();
391 QVERIFY(object != 0);
392 QCOMPARE(object->property("test").toInt(), 19);
397 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
398 QObject *object = component.create();
399 QVERIFY(object != 0);
400 QCOMPARE(object->property("test").toInt(), 19);
401 QCOMPARE(object->property("test2").toInt(), 17);
402 QCOMPARE(object->property("test3").toInt(), 16);
407 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
408 QObject *object = component.create();
409 QVERIFY(object != 0);
410 QCOMPARE(object->property("test").toInt(), 9);
415 void tst_qdeclarativeecmascript::bindingLoop()
417 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
418 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
419 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
420 QObject *object = component.create();
421 QVERIFY(object != 0);
425 void tst_qdeclarativeecmascript::basicExpressions_data()
427 QTest::addColumn<QString>("expression");
428 QTest::addColumn<QVariant>("result");
429 QTest::addColumn<bool>("nest");
431 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
432 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
433 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
434 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
435 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
436 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
437 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
438 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
439 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
440 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
441 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
442 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
443 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
444 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
445 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
446 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
447 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
448 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
449 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
452 void tst_qdeclarativeecmascript::basicExpressions()
454 QFETCH(QString, expression);
455 QFETCH(QVariant, result);
461 MyDefaultObject1 default1;
462 MyDefaultObject3 default3;
463 object1.setStringProperty("Object1");
464 object2.setStringProperty("Object2");
465 object3.setStringProperty("Object3");
467 QDeclarativeContext context(engine.rootContext());
468 QDeclarativeContext nestedContext(&context);
470 context.setContextObject(&default1);
471 context.setContextProperty("a", QVariant(1944));
472 context.setContextProperty("b", QVariant("Milk"));
473 context.setContextProperty("object", &object1);
474 context.setContextProperty("objectOverride", &object2);
475 nestedContext.setContextObject(&default3);
476 nestedContext.setContextProperty("b", QVariant("Cow"));
477 nestedContext.setContextProperty("objectOverride", &object3);
478 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
480 MyExpression expr(nest?&nestedContext:&context, expression);
481 QCOMPARE(expr.evaluate(), result);
484 void tst_qdeclarativeecmascript::arrayExpressions()
490 QDeclarativeContext context(engine.rootContext());
491 context.setContextProperty("a", &obj1);
492 context.setContextProperty("b", &obj2);
493 context.setContextProperty("c", &obj3);
495 MyExpression expr(&context, "[a, b, c, 10]");
496 QVariant result = expr.evaluate();
497 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
498 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
499 QCOMPARE(list.count(), 4);
500 QCOMPARE(list.at(0), &obj1);
501 QCOMPARE(list.at(1), &obj2);
502 QCOMPARE(list.at(2), &obj3);
503 QCOMPARE(list.at(3), (QObject *)0);
506 // Tests that modifying a context property will reevaluate expressions
507 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
509 QDeclarativeContext context(engine.rootContext());
512 MyQmlObject *object3 = new MyQmlObject;
514 object1.setStringProperty("Hello");
515 object2.setStringProperty("World");
517 context.setContextProperty("testProp", QVariant(1));
518 context.setContextProperty("testObj", &object1);
519 context.setContextProperty("testObj2", object3);
522 MyExpression expr(&context, "testProp + 1");
523 QCOMPARE(expr.changed, false);
524 QCOMPARE(expr.evaluate(), QVariant(2));
526 context.setContextProperty("testProp", QVariant(2));
527 QCOMPARE(expr.changed, true);
528 QCOMPARE(expr.evaluate(), QVariant(3));
532 MyExpression expr(&context, "testProp + testProp + testProp");
533 QCOMPARE(expr.changed, false);
534 QCOMPARE(expr.evaluate(), QVariant(6));
536 context.setContextProperty("testProp", QVariant(4));
537 QCOMPARE(expr.changed, true);
538 QCOMPARE(expr.evaluate(), QVariant(12));
542 MyExpression expr(&context, "testObj.stringProperty");
543 QCOMPARE(expr.changed, false);
544 QCOMPARE(expr.evaluate(), QVariant("Hello"));
546 context.setContextProperty("testObj", &object2);
547 QCOMPARE(expr.changed, true);
548 QCOMPARE(expr.evaluate(), QVariant("World"));
552 MyExpression expr(&context, "testObj.stringProperty /**/");
553 QCOMPARE(expr.changed, false);
554 QCOMPARE(expr.evaluate(), QVariant("World"));
556 context.setContextProperty("testObj", &object1);
557 QCOMPARE(expr.changed, true);
558 QCOMPARE(expr.evaluate(), QVariant("Hello"));
562 MyExpression expr(&context, "testObj2");
563 QCOMPARE(expr.changed, false);
564 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
570 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
572 QDeclarativeContext context(engine.rootContext());
576 context.setContextProperty("testObj", &object1);
578 object1.setStringProperty(QLatin1String("Hello"));
579 object2.setStringProperty(QLatin1String("Dog"));
580 object3.setStringProperty(QLatin1String("Cat"));
583 MyExpression expr(&context, "testObj.stringProperty");
584 QCOMPARE(expr.changed, false);
585 QCOMPARE(expr.evaluate(), QVariant("Hello"));
587 object1.setStringProperty(QLatin1String("World"));
588 QCOMPARE(expr.changed, true);
589 QCOMPARE(expr.evaluate(), QVariant("World"));
593 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
594 QCOMPARE(expr.changed, false);
595 QCOMPARE(expr.evaluate(), QVariant());
597 object1.setObjectProperty(&object2);
598 QCOMPARE(expr.changed, true);
599 expr.changed = false;
600 QCOMPARE(expr.evaluate(), QVariant("Dog"));
602 object1.setObjectProperty(&object3);
603 QCOMPARE(expr.changed, true);
604 expr.changed = false;
605 QCOMPARE(expr.evaluate(), QVariant("Cat"));
607 object1.setObjectProperty(0);
608 QCOMPARE(expr.changed, true);
609 expr.changed = false;
610 QCOMPARE(expr.evaluate(), QVariant());
612 object1.setObjectProperty(&object3);
613 QCOMPARE(expr.changed, true);
614 expr.changed = false;
615 QCOMPARE(expr.evaluate(), QVariant("Cat"));
617 object3.setStringProperty("Donkey");
618 QCOMPARE(expr.changed, true);
619 expr.changed = false;
620 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
624 void tst_qdeclarativeecmascript::deferredProperties()
626 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
627 MyDeferredObject *object =
628 qobject_cast<MyDeferredObject *>(component.create());
629 QVERIFY(object != 0);
630 QCOMPARE(object->value(), 0);
631 QVERIFY(object->objectProperty() == 0);
632 QVERIFY(object->objectProperty2() != 0);
633 qmlExecuteDeferred(object);
634 QCOMPARE(object->value(), 10);
635 QVERIFY(object->objectProperty() != 0);
636 MyQmlObject *qmlObject =
637 qobject_cast<MyQmlObject *>(object->objectProperty());
638 QVERIFY(qmlObject != 0);
639 QCOMPARE(qmlObject->value(), 10);
640 object->setValue(19);
641 QCOMPARE(qmlObject->value(), 19);
646 // Check errors on deferred properties are correctly emitted
647 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
649 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
650 MyDeferredObject *object =
651 qobject_cast<MyDeferredObject *>(component.create());
652 QVERIFY(object != 0);
653 QCOMPARE(object->value(), 0);
654 QVERIFY(object->objectProperty() == 0);
655 QVERIFY(object->objectProperty2() == 0);
657 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
658 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
660 qmlExecuteDeferred(object);
665 void tst_qdeclarativeecmascript::extensionObjects()
667 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
668 MyExtendedObject *object =
669 qobject_cast<MyExtendedObject *>(component.create());
670 QVERIFY(object != 0);
671 QCOMPARE(object->baseProperty(), 13);
672 QCOMPARE(object->coreProperty(), 9);
673 object->setProperty("extendedProperty", QVariant(11));
674 object->setProperty("baseExtendedProperty", QVariant(92));
675 QCOMPARE(object->coreProperty(), 11);
676 QCOMPARE(object->baseProperty(), 92);
678 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
680 QCOMPARE(nested->baseProperty(), 13);
681 QCOMPARE(nested->coreProperty(), 9);
682 nested->setProperty("extendedProperty", QVariant(11));
683 nested->setProperty("baseExtendedProperty", QVariant(92));
684 QCOMPARE(nested->coreProperty(), 11);
685 QCOMPARE(nested->baseProperty(), 92);
690 void tst_qdeclarativeecmascript::overrideExtensionProperties()
692 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
693 OverrideDefaultPropertyObject *object =
694 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
695 QVERIFY(object != 0);
696 QVERIFY(object->secondProperty() != 0);
697 QVERIFY(object->firstProperty() == 0);
702 void tst_qdeclarativeecmascript::attachedProperties()
705 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
706 QObject *object = component.create();
707 QVERIFY(object != 0);
708 QCOMPARE(object->property("a").toInt(), 19);
709 QCOMPARE(object->property("b").toInt(), 19);
710 QCOMPARE(object->property("c").toInt(), 19);
711 QCOMPARE(object->property("d").toInt(), 19);
716 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
717 QObject *object = component.create();
718 QVERIFY(object != 0);
719 QCOMPARE(object->property("a").toInt(), 26);
720 QCOMPARE(object->property("b").toInt(), 26);
721 QCOMPARE(object->property("c").toInt(), 26);
722 QCOMPARE(object->property("d").toInt(), 26);
728 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
729 QObject *object = component.create();
730 QVERIFY(object != 0);
732 QMetaObject::invokeMethod(object, "writeValue2");
734 MyQmlAttachedObject *attached =
735 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
736 QVERIFY(attached != 0);
738 QCOMPARE(attached->value2(), 9);
743 void tst_qdeclarativeecmascript::enums()
747 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
748 QObject *object = component.create();
749 QVERIFY(object != 0);
751 QCOMPARE(object->property("a").toInt(), 0);
752 QCOMPARE(object->property("b").toInt(), 1);
753 QCOMPARE(object->property("c").toInt(), 2);
754 QCOMPARE(object->property("d").toInt(), 3);
755 QCOMPARE(object->property("e").toInt(), 0);
756 QCOMPARE(object->property("f").toInt(), 1);
757 QCOMPARE(object->property("g").toInt(), 2);
758 QCOMPARE(object->property("h").toInt(), 3);
759 QCOMPARE(object->property("i").toInt(), 19);
760 QCOMPARE(object->property("j").toInt(), 19);
764 // Non-existent enums
766 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
768 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
769 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
770 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
771 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
773 QObject *object = component.create();
774 QVERIFY(object != 0);
775 QCOMPARE(object->property("a").toInt(), 0);
776 QCOMPARE(object->property("b").toInt(), 0);
782 void tst_qdeclarativeecmascript::valueTypeFunctions()
784 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
785 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
787 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
788 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
794 Tests that writing a constant to a property with a binding on it disables the
797 void tst_qdeclarativeecmascript::constantsOverrideBindings()
801 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
802 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
803 QVERIFY(object != 0);
805 QCOMPARE(object->property("c2").toInt(), 0);
806 object->setProperty("c1", QVariant(9));
807 QCOMPARE(object->property("c2").toInt(), 9);
809 emit object->basicSignal();
811 QCOMPARE(object->property("c2").toInt(), 13);
812 object->setProperty("c1", QVariant(8));
813 QCOMPARE(object->property("c2").toInt(), 13);
818 // During construction
820 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
821 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
822 QVERIFY(object != 0);
824 QCOMPARE(object->property("c1").toInt(), 0);
825 QCOMPARE(object->property("c2").toInt(), 10);
826 object->setProperty("c1", QVariant(9));
827 QCOMPARE(object->property("c1").toInt(), 9);
828 QCOMPARE(object->property("c2").toInt(), 10);
836 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
837 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
838 QVERIFY(object != 0);
840 QCOMPARE(object->property("c2").toInt(), 0);
841 object->setProperty("c1", QVariant(9));
842 QCOMPARE(object->property("c2").toInt(), 9);
844 object->setProperty("c2", QVariant(13));
845 QCOMPARE(object->property("c2").toInt(), 13);
846 object->setProperty("c1", QVariant(7));
847 QCOMPARE(object->property("c1").toInt(), 7);
848 QCOMPARE(object->property("c2").toInt(), 13);
856 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
857 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
858 QVERIFY(object != 0);
860 QCOMPARE(object->property("c1").toInt(), 0);
861 QCOMPARE(object->property("c3").toInt(), 10);
862 object->setProperty("c1", QVariant(9));
863 QCOMPARE(object->property("c1").toInt(), 9);
864 QCOMPARE(object->property("c3").toInt(), 10);
871 Tests that assigning a binding to a property that already has a binding causes
872 the original binding to be disabled.
874 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
876 QDeclarativeComponent component(&engine,
877 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
878 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
879 QVERIFY(object != 0);
881 QCOMPARE(object->property("c1").toInt(), 0);
882 QCOMPARE(object->property("c2").toInt(), 0);
883 QCOMPARE(object->property("c3").toInt(), 0);
885 object->setProperty("c1", QVariant(9));
886 QCOMPARE(object->property("c1").toInt(), 9);
887 QCOMPARE(object->property("c2").toInt(), 0);
888 QCOMPARE(object->property("c3").toInt(), 0);
890 object->setProperty("c3", QVariant(8));
891 QCOMPARE(object->property("c1").toInt(), 9);
892 QCOMPARE(object->property("c2").toInt(), 8);
893 QCOMPARE(object->property("c3").toInt(), 8);
899 Access a non-existent attached object.
901 Tests for a regression where this used to crash.
903 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
905 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
907 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
908 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
910 QObject *object = component.create();
911 QVERIFY(object != 0);
916 void tst_qdeclarativeecmascript::scope()
919 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
920 QObject *object = component.create();
921 QVERIFY(object != 0);
923 QCOMPARE(object->property("test1").toInt(), 1);
924 QCOMPARE(object->property("test2").toInt(), 2);
925 QCOMPARE(object->property("test3").toString(), QString("1Test"));
926 QCOMPARE(object->property("test4").toString(), QString("2Test"));
927 QCOMPARE(object->property("test5").toInt(), 1);
928 QCOMPARE(object->property("test6").toInt(), 1);
929 QCOMPARE(object->property("test7").toInt(), 2);
930 QCOMPARE(object->property("test8").toInt(), 2);
931 QCOMPARE(object->property("test9").toInt(), 1);
932 QCOMPARE(object->property("test10").toInt(), 3);
938 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
939 QObject *object = component.create();
940 QVERIFY(object != 0);
942 QCOMPARE(object->property("test1").toInt(), 19);
943 QCOMPARE(object->property("test2").toInt(), 19);
944 QCOMPARE(object->property("test3").toInt(), 14);
945 QCOMPARE(object->property("test4").toInt(), 14);
946 QCOMPARE(object->property("test5").toInt(), 24);
947 QCOMPARE(object->property("test6").toInt(), 24);
953 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
954 QObject *object = component.create();
955 QVERIFY(object != 0);
957 QCOMPARE(object->property("test1").toBool(), true);
958 QCOMPARE(object->property("test2").toBool(), true);
959 QCOMPARE(object->property("test3").toBool(), true);
964 // Signal argument scope
966 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
967 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
968 QVERIFY(object != 0);
970 QCOMPARE(object->property("test").toInt(), 0);
971 QCOMPARE(object->property("test2").toString(), QString());
973 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
975 QCOMPARE(object->property("test").toInt(), 13);
976 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
982 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
983 QObject *object = component.create();
984 QVERIFY(object != 0);
986 QCOMPARE(object->property("test1").toBool(), true);
987 QCOMPARE(object->property("test2").toBool(), true);
993 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
994 QObject *object = component.create();
995 QVERIFY(object != 0);
997 QCOMPARE(object->property("test").toBool(), true);
1003 // In 4.7, non-library javascript files that had no imports shared the imports of their
1004 // importing context
1005 void tst_qdeclarativeecmascript::importScope()
1007 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1008 QObject *o = component.create();
1011 QCOMPARE(o->property("test").toInt(), 240);
1017 Tests that "any" type passes through a synthesized signal parameter. This
1018 is essentially a test of QDeclarativeMetaType::copy()
1020 void tst_qdeclarativeecmascript::signalParameterTypes()
1022 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1023 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1024 QVERIFY(object != 0);
1026 emit object->basicSignal();
1028 QCOMPARE(object->property("intProperty").toInt(), 10);
1029 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1030 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1031 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1032 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1033 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1039 Test that two JS objects for the same QObject compare as equal.
1041 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1043 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1044 QObject *object = component.create();
1045 QVERIFY(object != 0);
1047 QCOMPARE(object->property("test1").toBool(), true);
1048 QCOMPARE(object->property("test2").toBool(), true);
1049 QCOMPARE(object->property("test3").toBool(), true);
1050 QCOMPARE(object->property("test4").toBool(), true);
1051 QCOMPARE(object->property("test5").toBool(), true);
1057 Confirm bindings and alias properties can coexist.
1059 Tests for a regression where the binding would not reevaluate.
1061 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1063 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1064 QObject *object = component.create();
1065 QVERIFY(object != 0);
1067 QCOMPARE(object->property("c2").toInt(), 3);
1068 QCOMPARE(object->property("c3").toInt(), 3);
1070 object->setProperty("c2", QVariant(19));
1072 QCOMPARE(object->property("c2").toInt(), 19);
1073 QCOMPARE(object->property("c3").toInt(), 19);
1079 Ensure that we can write undefined value to an alias property,
1080 and that the aliased property is reset correctly if possible.
1082 void tst_qdeclarativeecmascript::aliasPropertyReset()
1084 QObject *object = 0;
1086 // test that a manual write (of undefined) to a resettable aliased property succeeds
1087 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1088 object = c1.create();
1089 QVERIFY(object != 0);
1090 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1091 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1092 QMetaObject::invokeMethod(object, "resetAliased");
1093 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1094 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1097 // test that a manual write (of undefined) to a resettable alias property succeeds
1098 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1099 object = c2.create();
1100 QVERIFY(object != 0);
1101 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1102 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1103 QMetaObject::invokeMethod(object, "resetAlias");
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1105 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1108 // test that an alias to a bound property works correctly
1109 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1110 object = c3.create();
1111 QVERIFY(object != 0);
1112 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1113 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1114 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1115 QMetaObject::invokeMethod(object, "resetAlias");
1116 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1117 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1118 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1121 // test that a manual write (of undefined) to a resettable alias property
1122 // whose aliased property's object has been deleted, does not crash.
1123 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1124 object = c4.create();
1125 QVERIFY(object != 0);
1126 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1127 QObject *loader = object->findChild<QObject*>("loader");
1128 QVERIFY(loader != 0);
1130 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1131 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1132 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1133 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1134 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1137 // test that binding an alias property to an undefined value works correctly
1138 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1139 object = c5.create();
1140 QVERIFY(object != 0);
1141 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1144 // test that a manual write (of undefined) to a non-resettable property fails properly
1145 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1146 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1147 QDeclarativeComponent e1(&engine, url);
1148 object = e1.create();
1149 QVERIFY(object != 0);
1150 QCOMPARE(object->property("intAlias").value<int>(), 12);
1151 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1152 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1153 QMetaObject::invokeMethod(object, "resetAlias");
1154 QCOMPARE(object->property("intAlias").value<int>(), 12);
1155 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1159 void tst_qdeclarativeecmascript::dynamicCreation_data()
1161 QTest::addColumn<QString>("method");
1162 QTest::addColumn<QString>("createdName");
1164 QTest::newRow("One") << "createOne" << "objectOne";
1165 QTest::newRow("Two") << "createTwo" << "objectTwo";
1166 QTest::newRow("Three") << "createThree" << "objectThree";
1170 Test using createQmlObject to dynamically generate an item
1171 Also using createComponent is tested.
1173 void tst_qdeclarativeecmascript::dynamicCreation()
1175 QFETCH(QString, method);
1176 QFETCH(QString, createdName);
1178 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1179 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1180 QVERIFY(object != 0);
1182 QMetaObject::invokeMethod(object, method.toUtf8());
1183 QObject *created = object->objectProperty();
1185 QCOMPARE(created->objectName(), createdName);
1191 Tests the destroy function
1193 void tst_qdeclarativeecmascript::dynamicDestruction()
1196 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1197 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1198 QVERIFY(object != 0);
1199 QDeclarativeGuard<QObject> createdQmlObject = 0;
1201 QMetaObject::invokeMethod(object, "create");
1202 createdQmlObject = object->objectProperty();
1203 QVERIFY(createdQmlObject);
1204 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1206 QMetaObject::invokeMethod(object, "killOther");
1207 QVERIFY(createdQmlObject);
1208 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1209 QVERIFY(createdQmlObject);
1210 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1211 if (createdQmlObject) {
1213 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1216 QVERIFY(!createdQmlObject);
1218 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1219 QMetaObject::invokeMethod(object, "killMe");
1222 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1227 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1228 QObject *o = component.create();
1231 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1233 QMetaObject::invokeMethod(o, "create");
1235 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1237 QMetaObject::invokeMethod(o, "destroy");
1239 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1241 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1248 tests that id.toString() works
1250 void tst_qdeclarativeecmascript::objectToString()
1252 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1253 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1254 QVERIFY(object != 0);
1255 QMetaObject::invokeMethod(object, "testToString");
1256 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1257 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1263 tests that id.hasOwnProperty() works
1265 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1267 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1268 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1269 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1270 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1272 QDeclarativeComponent component(&engine, url);
1273 QObject *object = component.create();
1274 QVERIFY(object != 0);
1276 // test QObjects in QML
1277 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1278 QVERIFY(object->property("result").value<bool>() == true);
1279 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1280 QVERIFY(object->property("result").value<bool>() == false);
1282 // now test other types in QML
1283 QObject *child = object->findChild<QObject*>("typeObj");
1284 QVERIFY(child != 0);
1285 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1286 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1287 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1288 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1289 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1290 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1291 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1292 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1293 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1294 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1295 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1296 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1298 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1299 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1300 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1301 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1302 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1303 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1304 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1305 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1306 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1312 Tests bindings that indirectly cause their own deletion work.
1314 This test is best run under valgrind to ensure no invalid memory access occur.
1316 void tst_qdeclarativeecmascript::selfDeletingBinding()
1319 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1320 QObject *object = component.create();
1321 QVERIFY(object != 0);
1322 object->setProperty("triggerDelete", true);
1327 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1328 QObject *object = component.create();
1329 QVERIFY(object != 0);
1330 object->setProperty("triggerDelete", true);
1336 Test that extended object properties can be accessed.
1338 This test a regression where this used to crash. The issue was specificially
1339 for extended objects that did not include a synthesized meta object (so non-root
1340 and no synthesiszed properties).
1342 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1344 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1345 QObject *object = component.create();
1346 QVERIFY(object != 0);
1351 Test file/lineNumbers for binding/Script errors.
1353 void tst_qdeclarativeecmascript::scriptErrors()
1355 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1356 QString url = component.url().toString();
1358 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1359 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1360 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1361 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1362 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1363 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1364 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1365 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1367 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1368 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1369 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1370 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1371 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1372 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1373 QVERIFY(object != 0);
1375 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1376 emit object->basicSignal();
1378 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1379 emit object->anotherBasicSignal();
1381 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1382 emit object->thirdBasicSignal();
1388 Test file/lineNumbers for inline functions.
1390 void tst_qdeclarativeecmascript::functionErrors()
1392 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1393 QString url = component.url().toString();
1395 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1397 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1399 QObject *object = component.create();
1400 QVERIFY(object != 0);
1403 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1404 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1405 url = componentTwo.url().toString();
1406 object = componentTwo.create();
1407 QVERIFY(object != 0);
1409 QString srpname = object->property("srp_name").toString();
1411 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1412 QLatin1String(" is not a function");
1413 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1414 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1419 Test various errors that can occur when assigning a property from script
1421 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1423 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1425 QString url = component.url().toString();
1427 QObject *object = component.create();
1428 QVERIFY(object != 0);
1430 QCOMPARE(object->property("test1").toBool(), true);
1431 QCOMPARE(object->property("test2").toBool(), true);
1437 Test bindings still work when the reeval is triggered from within
1440 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1442 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1443 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1444 QVERIFY(object != 0);
1446 QCOMPARE(object->property("base").toReal(), 50.);
1447 QCOMPARE(object->property("test1").toReal(), 50.);
1448 QCOMPARE(object->property("test2").toReal(), 50.);
1450 object->basicSignal();
1452 QCOMPARE(object->property("base").toReal(), 200.);
1453 QCOMPARE(object->property("test1").toReal(), 200.);
1454 QCOMPARE(object->property("test2").toReal(), 200.);
1456 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1458 QCOMPARE(object->property("base").toReal(), 400.);
1459 QCOMPARE(object->property("test1").toReal(), 400.);
1460 QCOMPARE(object->property("test2").toReal(), 400.);
1466 Test that list properties can be iterated from ECMAScript
1468 void tst_qdeclarativeecmascript::listProperties()
1470 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1471 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1472 QVERIFY(object != 0);
1474 QCOMPARE(object->property("test1").toInt(), 21);
1475 QCOMPARE(object->property("test2").toInt(), 2);
1476 QCOMPARE(object->property("test3").toBool(), true);
1477 QCOMPARE(object->property("test4").toBool(), true);
1482 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1484 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1485 QString url = component.url().toString();
1487 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1489 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1490 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1491 QVERIFY(object != 0);
1493 QCOMPARE(object->property("test").toBool(), false);
1495 MyQmlObject object2;
1496 MyQmlObject object3;
1497 object2.setObjectProperty(&object3);
1498 object->setObjectProperty(&object2);
1500 QCOMPARE(object->property("test").toBool(), true);
1505 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1507 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1508 QString url = component.url().toString();
1510 QString warning = component.url().toString() + ":6: Error: JS exception";
1512 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1513 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1514 QVERIFY(object != 0);
1518 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1520 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1521 QString url = component.url().toString();
1523 QString warning = component.url().toString() + ":5: Error: JS exception";
1525 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1526 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1527 QVERIFY(object != 0);
1531 static int transientErrorsMsgCount = 0;
1532 static void transientErrorsMsgHandler(QtMsgType, const char *)
1534 ++transientErrorsMsgCount;
1537 // Check that transient binding errors are not displayed
1538 void tst_qdeclarativeecmascript::transientErrors()
1541 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1543 transientErrorsMsgCount = 0;
1544 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1546 QObject *object = component.create();
1547 QVERIFY(object != 0);
1549 qInstallMsgHandler(old);
1551 QCOMPARE(transientErrorsMsgCount, 0);
1556 // One binding erroring multiple times, but then resolving
1558 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1560 transientErrorsMsgCount = 0;
1561 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1563 QObject *object = component.create();
1564 QVERIFY(object != 0);
1566 qInstallMsgHandler(old);
1568 QCOMPARE(transientErrorsMsgCount, 0);
1574 // Check that errors during shutdown are minimized
1575 void tst_qdeclarativeecmascript::shutdownErrors()
1577 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1578 QObject *object = component.create();
1579 QVERIFY(object != 0);
1581 transientErrorsMsgCount = 0;
1582 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1586 qInstallMsgHandler(old);
1587 QCOMPARE(transientErrorsMsgCount, 0);
1590 void tst_qdeclarativeecmascript::compositePropertyType()
1592 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1593 QString messageFormat = QString(QLatin1String("hello world (%1:%2)")).arg(TEST_FILE("compositePropertyType.qml").toString()).arg(7);
1594 QTest::ignoreMessage(QtDebugMsg, qPrintable(messageFormat));
1595 QObject *object = qobject_cast<QObject *>(component.create());
1600 void tst_qdeclarativeecmascript::jsObject()
1602 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1603 QObject *object = component.create();
1604 QVERIFY(object != 0);
1606 QCOMPARE(object->property("test").toInt(), 92);
1611 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1614 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1615 QObject *object = component.create();
1616 QVERIFY(object != 0);
1618 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1620 object->setProperty("setUndefined", true);
1622 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1624 object->setProperty("setUndefined", false);
1626 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1631 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1632 QObject *object = component.create();
1633 QVERIFY(object != 0);
1635 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1637 QMetaObject::invokeMethod(object, "doReset");
1639 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1646 void tst_qdeclarativeecmascript::bug1()
1648 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1649 QObject *object = component.create();
1650 QVERIFY(object != 0);
1652 QCOMPARE(object->property("test").toInt(), 14);
1654 object->setProperty("a", 11);
1656 QCOMPARE(object->property("test").toInt(), 3);
1658 object->setProperty("b", true);
1660 QCOMPARE(object->property("test").toInt(), 9);
1665 void tst_qdeclarativeecmascript::bug2()
1667 QDeclarativeComponent component(&engine);
1668 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1670 QObject *object = component.create();
1671 QVERIFY(object != 0);
1676 // Don't crash in createObject when the component has errors.
1677 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1679 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1680 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1681 QVERIFY(object != 0);
1683 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1684 QMetaObject::invokeMethod(object, "dontCrash");
1685 QObject *created = object->objectProperty();
1686 QVERIFY(created == 0);
1691 // ownership transferred to JS, ensure that GC runs the dtor
1692 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1695 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1697 // allow the engine to go out of scope too.
1699 QDeclarativeEngine dcoEngine;
1700 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1701 QObject *object = component.create();
1702 QVERIFY(object != 0);
1703 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1704 QVERIFY(mdcdo != 0);
1705 mdcdo->setDtorCount(&dtorCount);
1707 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1708 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1710 // we do this once manually, but it should be done automatically
1711 // when the engine goes out of scope (since it should gc in dtor)
1712 QMetaObject::invokeMethod(object, "performGc");
1715 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1721 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1722 QCOMPARE(dtorCount, expectedDtorCount);
1726 void tst_qdeclarativeecmascript::regExpBug()
1728 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1729 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1730 QVERIFY(object != 0);
1731 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1735 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1737 QString functionSource = QLatin1String("(function(object) { return ") +
1738 QLatin1String(source) + QLatin1String(" })");
1740 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1743 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1744 if (function.IsEmpty())
1746 v8::Handle<v8::Value> args[] = { o };
1747 function->Call(engine->global(), 1, args);
1748 return tc.HasCaught();
1751 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1752 const char *source, v8::Handle<v8::Value> result)
1754 QString functionSource = QLatin1String("(function(object) { return ") +
1755 QLatin1String(source) + QLatin1String(" })");
1757 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1760 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1761 if (function.IsEmpty())
1763 v8::Handle<v8::Value> args[] = { o };
1765 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1770 return value->StrictEquals(result);
1773 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1776 QString functionSource = QLatin1String("(function(object) { return ") +
1777 QLatin1String(source) + QLatin1String(" })");
1779 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1781 return v8::Handle<v8::Value>();
1782 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1783 if (function.IsEmpty())
1784 return v8::Handle<v8::Value>();
1785 v8::Handle<v8::Value> args[] = { o };
1787 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1790 return v8::Handle<v8::Value>();
1794 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1795 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1796 #define EVALUATE(source) evaluate(engine, object, source)
1798 void tst_qdeclarativeecmascript::callQtInvokables()
1800 MyInvokableObject o;
1802 QDeclarativeEngine qmlengine;
1803 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1805 QV8Engine *engine = ep->v8engine();
1807 v8::HandleScope handle_scope;
1808 v8::Context::Scope scope(engine->context());
1810 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1812 // Non-existent methods
1814 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1815 QCOMPARE(o.error(), false);
1816 QCOMPARE(o.invoked(), -1);
1817 QCOMPARE(o.actuals().count(), 0);
1820 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1821 QCOMPARE(o.error(), false);
1822 QCOMPARE(o.invoked(), -1);
1823 QCOMPARE(o.actuals().count(), 0);
1825 // Insufficient arguments
1827 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1828 QCOMPARE(o.error(), false);
1829 QCOMPARE(o.invoked(), -1);
1830 QCOMPARE(o.actuals().count(), 0);
1833 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1834 QCOMPARE(o.error(), false);
1835 QCOMPARE(o.invoked(), -1);
1836 QCOMPARE(o.actuals().count(), 0);
1838 // Excessive arguments
1840 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1841 QCOMPARE(o.error(), false);
1842 QCOMPARE(o.invoked(), 8);
1843 QCOMPARE(o.actuals().count(), 1);
1844 QCOMPARE(o.actuals().at(0), QVariant(10));
1847 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1848 QCOMPARE(o.error(), false);
1849 QCOMPARE(o.invoked(), 9);
1850 QCOMPARE(o.actuals().count(), 2);
1851 QCOMPARE(o.actuals().at(0), QVariant(10));
1852 QCOMPARE(o.actuals().at(1), QVariant(11));
1854 // Test return types
1856 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1857 QCOMPARE(o.error(), false);
1858 QCOMPARE(o.invoked(), 0);
1859 QCOMPARE(o.actuals().count(), 0);
1862 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1863 QCOMPARE(o.error(), false);
1864 QCOMPARE(o.invoked(), 1);
1865 QCOMPARE(o.actuals().count(), 0);
1868 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1869 QCOMPARE(o.error(), false);
1870 QCOMPARE(o.invoked(), 2);
1871 QCOMPARE(o.actuals().count(), 0);
1875 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1876 QVERIFY(!ret.IsEmpty());
1877 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1878 QCOMPARE(o.error(), false);
1879 QCOMPARE(o.invoked(), 3);
1880 QCOMPARE(o.actuals().count(), 0);
1885 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1886 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1887 QCOMPARE(o.error(), false);
1888 QCOMPARE(o.invoked(), 4);
1889 QCOMPARE(o.actuals().count(), 0);
1893 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1894 QCOMPARE(o.error(), false);
1895 QCOMPARE(o.invoked(), 5);
1896 QCOMPARE(o.actuals().count(), 0);
1900 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1901 QVERIFY(ret->IsString());
1902 QCOMPARE(engine->toString(ret), QString("Hello world"));
1903 QCOMPARE(o.error(), false);
1904 QCOMPARE(o.invoked(), 6);
1905 QCOMPARE(o.actuals().count(), 0);
1909 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1910 QCOMPARE(o.error(), false);
1911 QCOMPARE(o.invoked(), 7);
1912 QCOMPARE(o.actuals().count(), 0);
1916 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1917 QCOMPARE(o.error(), false);
1918 QCOMPARE(o.invoked(), 8);
1919 QCOMPARE(o.actuals().count(), 1);
1920 QCOMPARE(o.actuals().at(0), QVariant(94));
1923 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1924 QCOMPARE(o.error(), false);
1925 QCOMPARE(o.invoked(), 8);
1926 QCOMPARE(o.actuals().count(), 1);
1927 QCOMPARE(o.actuals().at(0), QVariant(94));
1930 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1931 QCOMPARE(o.error(), false);
1932 QCOMPARE(o.invoked(), 8);
1933 QCOMPARE(o.actuals().count(), 1);
1934 QCOMPARE(o.actuals().at(0), QVariant(0));
1937 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1938 QCOMPARE(o.error(), false);
1939 QCOMPARE(o.invoked(), 8);
1940 QCOMPARE(o.actuals().count(), 1);
1941 QCOMPARE(o.actuals().at(0), QVariant(0));
1944 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1945 QCOMPARE(o.error(), false);
1946 QCOMPARE(o.invoked(), 8);
1947 QCOMPARE(o.actuals().count(), 1);
1948 QCOMPARE(o.actuals().at(0), QVariant(0));
1951 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1952 QCOMPARE(o.error(), false);
1953 QCOMPARE(o.invoked(), 8);
1954 QCOMPARE(o.actuals().count(), 1);
1955 QCOMPARE(o.actuals().at(0), QVariant(0));
1958 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1959 QCOMPARE(o.error(), false);
1960 QCOMPARE(o.invoked(), 9);
1961 QCOMPARE(o.actuals().count(), 2);
1962 QCOMPARE(o.actuals().at(0), QVariant(122));
1963 QCOMPARE(o.actuals().at(1), QVariant(9));
1966 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1967 QCOMPARE(o.error(), false);
1968 QCOMPARE(o.invoked(), 10);
1969 QCOMPARE(o.actuals().count(), 1);
1970 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1973 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1974 QCOMPARE(o.error(), false);
1975 QCOMPARE(o.invoked(), 10);
1976 QCOMPARE(o.actuals().count(), 1);
1977 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1980 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1981 QCOMPARE(o.error(), false);
1982 QCOMPARE(o.invoked(), 10);
1983 QCOMPARE(o.actuals().count(), 1);
1984 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1987 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1988 QCOMPARE(o.error(), false);
1989 QCOMPARE(o.invoked(), 10);
1990 QCOMPARE(o.actuals().count(), 1);
1991 QCOMPARE(o.actuals().at(0), QVariant(0));
1994 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1995 QCOMPARE(o.error(), false);
1996 QCOMPARE(o.invoked(), 10);
1997 QCOMPARE(o.actuals().count(), 1);
1998 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2001 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2002 QCOMPARE(o.error(), false);
2003 QCOMPARE(o.invoked(), 10);
2004 QCOMPARE(o.actuals().count(), 1);
2005 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2008 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2009 QCOMPARE(o.error(), false);
2010 QCOMPARE(o.invoked(), 11);
2011 QCOMPARE(o.actuals().count(), 1);
2012 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2015 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2016 QCOMPARE(o.error(), false);
2017 QCOMPARE(o.invoked(), 11);
2018 QCOMPARE(o.actuals().count(), 1);
2019 QCOMPARE(o.actuals().at(0), QVariant("19"));
2023 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2024 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2025 QCOMPARE(o.error(), false);
2026 QCOMPARE(o.invoked(), 11);
2027 QCOMPARE(o.actuals().count(), 1);
2028 QCOMPARE(o.actuals().at(0), QVariant(expected));
2032 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2033 QCOMPARE(o.error(), false);
2034 QCOMPARE(o.invoked(), 11);
2035 QCOMPARE(o.actuals().count(), 1);
2036 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2039 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2040 QCOMPARE(o.error(), false);
2041 QCOMPARE(o.invoked(), 11);
2042 QCOMPARE(o.actuals().count(), 1);
2043 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2046 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2047 QCOMPARE(o.error(), false);
2048 QCOMPARE(o.invoked(), 12);
2049 QCOMPARE(o.actuals().count(), 1);
2050 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2053 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2054 QCOMPARE(o.error(), false);
2055 QCOMPARE(o.invoked(), 12);
2056 QCOMPARE(o.actuals().count(), 1);
2057 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2060 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2061 QCOMPARE(o.error(), false);
2062 QCOMPARE(o.invoked(), 12);
2063 QCOMPARE(o.actuals().count(), 1);
2064 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2067 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2068 QCOMPARE(o.error(), false);
2069 QCOMPARE(o.invoked(), 12);
2070 QCOMPARE(o.actuals().count(), 1);
2071 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2074 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2075 QCOMPARE(o.error(), false);
2076 QCOMPARE(o.invoked(), 12);
2077 QCOMPARE(o.actuals().count(), 1);
2078 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2081 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2082 QCOMPARE(o.error(), false);
2083 QCOMPARE(o.invoked(), 12);
2084 QCOMPARE(o.actuals().count(), 1);
2085 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2088 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2089 QCOMPARE(o.error(), false);
2090 QCOMPARE(o.invoked(), 13);
2091 QCOMPARE(o.actuals().count(), 1);
2092 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2095 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2096 QCOMPARE(o.error(), false);
2097 QCOMPARE(o.invoked(), 13);
2098 QCOMPARE(o.actuals().count(), 1);
2099 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2102 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2103 QCOMPARE(o.error(), false);
2104 QCOMPARE(o.invoked(), 13);
2105 QCOMPARE(o.actuals().count(), 1);
2106 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2109 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2110 QCOMPARE(o.error(), false);
2111 QCOMPARE(o.invoked(), 13);
2112 QCOMPARE(o.actuals().count(), 1);
2113 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2116 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2117 QCOMPARE(o.error(), false);
2118 QCOMPARE(o.invoked(), 13);
2119 QCOMPARE(o.actuals().count(), 1);
2120 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2123 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2124 QCOMPARE(o.error(), false);
2125 QCOMPARE(o.invoked(), 14);
2126 QCOMPARE(o.actuals().count(), 1);
2127 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2130 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2131 QCOMPARE(o.error(), false);
2132 QCOMPARE(o.invoked(), 14);
2133 QCOMPARE(o.actuals().count(), 1);
2134 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2137 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2138 QCOMPARE(o.error(), false);
2139 QCOMPARE(o.invoked(), 14);
2140 QCOMPARE(o.actuals().count(), 1);
2141 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2144 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2145 QCOMPARE(o.error(), false);
2146 QCOMPARE(o.invoked(), 14);
2147 QCOMPARE(o.actuals().count(), 1);
2148 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2151 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2152 QCOMPARE(o.error(), false);
2153 QCOMPARE(o.invoked(), 15);
2154 QCOMPARE(o.actuals().count(), 2);
2155 QCOMPARE(o.actuals().at(0), QVariant(4));
2156 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2159 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2160 QCOMPARE(o.error(), false);
2161 QCOMPARE(o.invoked(), 15);
2162 QCOMPARE(o.actuals().count(), 2);
2163 QCOMPARE(o.actuals().at(0), QVariant(8));
2164 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2167 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2168 QCOMPARE(o.error(), false);
2169 QCOMPARE(o.invoked(), 15);
2170 QCOMPARE(o.actuals().count(), 2);
2171 QCOMPARE(o.actuals().at(0), QVariant(3));
2172 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2175 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2176 QCOMPARE(o.error(), false);
2177 QCOMPARE(o.invoked(), 15);
2178 QCOMPARE(o.actuals().count(), 2);
2179 QCOMPARE(o.actuals().at(0), QVariant(44));
2180 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2183 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2184 QCOMPARE(o.error(), false);
2185 QCOMPARE(o.invoked(), -1);
2186 QCOMPARE(o.actuals().count(), 0);
2189 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2190 QCOMPARE(o.error(), false);
2191 QCOMPARE(o.invoked(), 16);
2192 QCOMPARE(o.actuals().count(), 1);
2193 QCOMPARE(o.actuals().at(0), QVariant(10));
2196 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2197 QCOMPARE(o.error(), false);
2198 QCOMPARE(o.invoked(), 17);
2199 QCOMPARE(o.actuals().count(), 2);
2200 QCOMPARE(o.actuals().at(0), QVariant(10));
2201 QCOMPARE(o.actuals().at(1), QVariant(11));
2204 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2205 QCOMPARE(o.error(), false);
2206 QCOMPARE(o.invoked(), 18);
2207 QCOMPARE(o.actuals().count(), 1);
2208 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2211 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2212 QCOMPARE(o.error(), false);
2213 QCOMPARE(o.invoked(), 19);
2214 QCOMPARE(o.actuals().count(), 1);
2215 QCOMPARE(o.actuals().at(0), QVariant(9));
2218 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2219 QCOMPARE(o.error(), false);
2220 QCOMPARE(o.invoked(), 20);
2221 QCOMPARE(o.actuals().count(), 2);
2222 QCOMPARE(o.actuals().at(0), QVariant(10));
2223 QCOMPARE(o.actuals().at(1), QVariant(19));
2226 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2227 QCOMPARE(o.error(), false);
2228 QCOMPARE(o.invoked(), 20);
2229 QCOMPARE(o.actuals().count(), 2);
2230 QCOMPARE(o.actuals().at(0), QVariant(10));
2231 QCOMPARE(o.actuals().at(1), QVariant(13));
2234 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2235 QCOMPARE(o.error(), false);
2236 QCOMPARE(o.invoked(), -3);
2237 QCOMPARE(o.actuals().count(), 1);
2238 QCOMPARE(o.actuals().at(0), QVariant(9));
2241 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2242 QCOMPARE(o.error(), false);
2243 QCOMPARE(o.invoked(), 21);
2244 QCOMPARE(o.actuals().count(), 2);
2245 QCOMPARE(o.actuals().at(0), QVariant(9));
2246 QCOMPARE(o.actuals().at(1), QVariant());
2249 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2250 QCOMPARE(o.error(), false);
2251 QCOMPARE(o.invoked(), 21);
2252 QCOMPARE(o.actuals().count(), 2);
2253 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2254 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2257 // QTBUG-13047 (check that you can pass registered object types as args)
2258 void tst_qdeclarativeecmascript::invokableObjectArg()
2260 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2262 QObject *o = component.create();
2264 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2266 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2271 // QTBUG-13047 (check that you can return registered object types from methods)
2272 void tst_qdeclarativeecmascript::invokableObjectRet()
2274 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2276 QObject *o = component.create();
2278 QCOMPARE(o->property("test").toBool(), true);
2283 void tst_qdeclarativeecmascript::listToVariant()
2285 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2287 MyQmlContainer container;
2289 QDeclarativeContext context(engine.rootContext());
2290 context.setContextObject(&container);
2292 QObject *object = component.create(&context);
2293 QVERIFY(object != 0);
2295 QVariant v = object->property("test");
2296 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2297 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2303 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2304 void tst_qdeclarativeecmascript::listAssignment()
2306 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2307 QObject *obj = component.create();
2308 QCOMPARE(obj->property("list1length").toInt(), 2);
2309 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2310 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2311 QCOMPARE(list1.count(&list1), list2.count(&list2));
2312 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2313 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2318 void tst_qdeclarativeecmascript::multiEngineObject()
2321 obj.setStringProperty("Howdy planet");
2323 QDeclarativeEngine e1;
2324 e1.rootContext()->setContextProperty("thing", &obj);
2325 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2327 QDeclarativeEngine e2;
2328 e2.rootContext()->setContextProperty("thing", &obj);
2329 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2331 QObject *o1 = c1.create();
2332 QObject *o2 = c2.create();
2334 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2335 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2341 // Test that references to QObjects are cleanup when the object is destroyed
2342 void tst_qdeclarativeecmascript::deletedObject()
2344 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2346 QObject *object = component.create();
2348 QCOMPARE(object->property("test1").toBool(), true);
2349 QCOMPARE(object->property("test2").toBool(), true);
2350 QCOMPARE(object->property("test3").toBool(), true);
2351 QCOMPARE(object->property("test4").toBool(), true);
2356 void tst_qdeclarativeecmascript::attachedPropertyScope()
2358 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2360 QObject *object = component.create();
2361 QVERIFY(object != 0);
2363 MyQmlAttachedObject *attached =
2364 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2365 QVERIFY(attached != 0);
2367 QCOMPARE(object->property("value2").toInt(), 0);
2369 attached->emitMySignal();
2371 QCOMPARE(object->property("value2").toInt(), 9);
2376 void tst_qdeclarativeecmascript::scriptConnect()
2379 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2381 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2382 QVERIFY(object != 0);
2384 QCOMPARE(object->property("test").toBool(), false);
2385 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2386 QCOMPARE(object->property("test").toBool(), true);
2392 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.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.3.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.4.qml"));
2420 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2421 QVERIFY(object != 0);
2423 QCOMPARE(object->methodCalled(), false);
2424 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2425 QCOMPARE(object->methodCalled(), true);
2431 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.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.6.qml"));
2446 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2447 QVERIFY(object != 0);
2449 QCOMPARE(object->property("test").toInt(), 0);
2450 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2451 QCOMPARE(object->property("test").toInt(), 2);
2457 void tst_qdeclarativeecmascript::scriptDisconnect()
2460 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2462 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2463 QVERIFY(object != 0);
2465 QCOMPARE(object->property("test").toInt(), 0);
2466 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2467 QCOMPARE(object->property("test").toInt(), 1);
2468 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2469 QCOMPARE(object->property("test").toInt(), 2);
2470 emit object->basicSignal();
2471 QCOMPARE(object->property("test").toInt(), 2);
2472 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2473 QCOMPARE(object->property("test").toInt(), 2);
2479 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2481 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2482 QVERIFY(object != 0);
2484 QCOMPARE(object->property("test").toInt(), 0);
2485 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2486 QCOMPARE(object->property("test").toInt(), 1);
2487 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2488 QCOMPARE(object->property("test").toInt(), 2);
2489 emit object->basicSignal();
2490 QCOMPARE(object->property("test").toInt(), 2);
2491 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2492 QCOMPARE(object->property("test").toInt(), 2);
2498 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2500 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2501 QVERIFY(object != 0);
2503 QCOMPARE(object->property("test").toInt(), 0);
2504 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2505 QCOMPARE(object->property("test").toInt(), 1);
2506 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2507 QCOMPARE(object->property("test").toInt(), 2);
2508 emit object->basicSignal();
2509 QCOMPARE(object->property("test").toInt(), 2);
2510 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2511 QCOMPARE(object->property("test").toInt(), 3);
2516 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2518 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2519 QVERIFY(object != 0);
2521 QCOMPARE(object->property("test").toInt(), 0);
2522 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2523 QCOMPARE(object->property("test").toInt(), 1);
2524 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2525 QCOMPARE(object->property("test").toInt(), 2);
2526 emit object->basicSignal();
2527 QCOMPARE(object->property("test").toInt(), 2);
2528 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2529 QCOMPARE(object->property("test").toInt(), 3);
2535 class OwnershipObject : public QObject
2539 OwnershipObject() { object = new QObject; }
2541 QPointer<QObject> object;
2544 QObject *getObject() { return object; }
2547 void tst_qdeclarativeecmascript::ownership()
2549 OwnershipObject own;
2550 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2551 context->setContextObject(&own);
2554 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2556 QVERIFY(own.object != 0);
2558 QObject *object = component.create(context);
2560 engine.collectGarbage();
2562 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2564 QVERIFY(own.object == 0);
2569 own.object = new QObject(&own);
2572 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2574 QVERIFY(own.object != 0);
2576 QObject *object = component.create(context);
2578 engine.collectGarbage();
2580 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2582 QVERIFY(own.object != 0);
2590 class CppOwnershipReturnValue : public QObject
2594 CppOwnershipReturnValue() : value(0) {}
2595 ~CppOwnershipReturnValue() { delete value; }
2597 Q_INVOKABLE QObject *create() {
2598 value = new QObject;
2599 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2603 Q_INVOKABLE MyQmlObject *createQmlObject() {
2604 MyQmlObject *rv = new MyQmlObject;
2609 QPointer<QObject> value;
2613 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2614 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2616 CppOwnershipReturnValue source;
2619 QDeclarativeEngine engine;
2620 engine.rootContext()->setContextProperty("source", &source);
2622 QVERIFY(source.value == 0);
2624 QDeclarativeComponent component(&engine);
2625 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2627 QObject *object = component.create();
2629 QVERIFY(object != 0);
2630 QVERIFY(source.value != 0);
2635 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2637 QVERIFY(source.value != 0);
2641 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2643 CppOwnershipReturnValue source;
2646 QDeclarativeEngine engine;
2647 engine.rootContext()->setContextProperty("source", &source);
2649 QVERIFY(source.value == 0);
2651 QDeclarativeComponent component(&engine);
2652 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2654 QObject *object = component.create();
2656 QVERIFY(object != 0);
2657 QVERIFY(source.value != 0);
2662 engine.collectGarbage();
2663 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2665 QVERIFY(source.value == 0);
2668 class QListQObjectMethodsObject : public QObject
2672 QListQObjectMethodsObject() {
2673 m_objects.append(new MyQmlObject());
2674 m_objects.append(new MyQmlObject());
2677 ~QListQObjectMethodsObject() {
2678 qDeleteAll(m_objects);
2682 QList<QObject *> getObjects() { return m_objects; }
2685 QList<QObject *> m_objects;
2688 // Tests that returning a QList<QObject*> from a method works
2689 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2691 QListQObjectMethodsObject obj;
2692 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2693 context->setContextObject(&obj);
2695 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2697 QObject *object = component.create(context);
2699 QCOMPARE(object->property("test").toInt(), 2);
2700 QCOMPARE(object->property("test2").toBool(), true);
2707 void tst_qdeclarativeecmascript::strictlyEquals()
2709 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2711 QObject *object = component.create();
2712 QVERIFY(object != 0);
2714 QCOMPARE(object->property("test1").toBool(), true);
2715 QCOMPARE(object->property("test2").toBool(), true);
2716 QCOMPARE(object->property("test3").toBool(), true);
2717 QCOMPARE(object->property("test4").toBool(), true);
2718 QCOMPARE(object->property("test5").toBool(), true);
2719 QCOMPARE(object->property("test6").toBool(), true);
2720 QCOMPARE(object->property("test7").toBool(), true);
2721 QCOMPARE(object->property("test8").toBool(), true);
2726 void tst_qdeclarativeecmascript::compiled()
2728 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2730 QObject *object = component.create();
2731 QVERIFY(object != 0);
2733 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2734 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2735 QCOMPARE(object->property("test3").toBool(), true);
2736 QCOMPARE(object->property("test4").toBool(), false);
2737 QCOMPARE(object->property("test5").toBool(), false);
2738 QCOMPARE(object->property("test6").toBool(), true);
2740 QCOMPARE(object->property("test7").toInt(), 185);
2741 QCOMPARE(object->property("test8").toInt(), 167);
2742 QCOMPARE(object->property("test9").toBool(), true);
2743 QCOMPARE(object->property("test10").toBool(), false);
2744 QCOMPARE(object->property("test11").toBool(), false);
2745 QCOMPARE(object->property("test12").toBool(), true);
2747 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2748 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2749 QCOMPARE(object->property("test15").toBool(), false);
2750 QCOMPARE(object->property("test16").toBool(), true);
2752 QCOMPARE(object->property("test17").toInt(), 5);
2753 QCOMPARE(object->property("test18").toReal(), qreal(176));
2754 QCOMPARE(object->property("test19").toInt(), 7);
2755 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2756 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2757 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2758 QCOMPARE(object->property("test23").toBool(), true);
2759 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2760 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2765 // Test that numbers assigned in bindings as strings work consistently
2766 void tst_qdeclarativeecmascript::numberAssignment()
2768 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2770 QObject *object = component.create();
2771 QVERIFY(object != 0);
2773 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2774 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2775 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2776 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2777 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2779 QCOMPARE(object->property("test5"), QVariant((int)7));
2780 QCOMPARE(object->property("test6"), QVariant((int)7));
2781 QCOMPARE(object->property("test7"), QVariant((int)6));
2782 QCOMPARE(object->property("test8"), QVariant((int)6));
2784 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2785 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2786 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2787 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2792 void tst_qdeclarativeecmascript::propertySplicing()
2794 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2796 QObject *object = component.create();
2797 QVERIFY(object != 0);
2799 QCOMPARE(object->property("test").toBool(), true);
2805 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2807 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2809 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2810 QVERIFY(object != 0);
2812 MyQmlObject::MyType type;
2813 type.value = 0x8971123;
2814 emit object->signalWithUnknownType(type);
2816 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2818 QCOMPARE(result.value, type.value);
2824 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2826 QTest::addColumn<QString>("expression");
2827 QTest::addColumn<QString>("compare");
2829 QString compareStrict("(function(a, b) { return a === b; })");
2830 QTest::newRow("true") << "true" << compareStrict;
2831 QTest::newRow("undefined") << "undefined" << compareStrict;
2832 QTest::newRow("null") << "null" << compareStrict;
2833 QTest::newRow("123") << "123" << compareStrict;
2834 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2836 QString comparePropertiesStrict(
2838 " if (typeof b != 'object')"
2840 " var props = Object.getOwnPropertyNames(b);"
2841 " for (var i = 0; i < props.length; ++i) {"
2842 " var p = props[i];"
2843 " return arguments.callee(a[p], b[p]);"
2846 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2847 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2850 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2852 QFETCH(QString, expression);
2853 QFETCH(QString, compare);
2855 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2856 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2857 QVERIFY(object != 0);
2859 QJSValue value = engine.evaluate(expression);
2860 QVERIFY(!engine.hasUncaughtException());
2861 object->setProperty("expression", expression);
2862 object->setProperty("compare", compare);
2863 object->setProperty("pass", false);
2865 emit object->signalWithVariant(QVariant::fromValue(value));
2866 QVERIFY(object->property("pass").toBool());
2869 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2871 signalWithJSValueInVariant_data();
2874 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2876 QFETCH(QString, expression);
2877 QFETCH(QString, compare);
2879 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2880 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2881 QVERIFY(object != 0);
2884 QJSValue value = engine2.evaluate(expression);
2885 QVERIFY(!engine2.hasUncaughtException());
2886 object->setProperty("expression", expression);
2887 object->setProperty("compare", compare);
2888 object->setProperty("pass", false);
2890 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2891 emit object->signalWithVariant(QVariant::fromValue(value));
2892 QVERIFY(!object->property("pass").toBool());
2895 void tst_qdeclarativeecmascript::moduleApi_data()
2897 QTest::addColumn<QUrl>("testfile");
2898 QTest::addColumn<QString>("errorMessage");
2899 QTest::addColumn<QStringList>("warningMessages");
2900 QTest::addColumn<QStringList>("readProperties");
2901 QTest::addColumn<QVariantList>("readExpectedValues");
2902 QTest::addColumn<QStringList>("writeProperties");
2903 QTest::addColumn<QVariantList>("writeValues");
2904 QTest::addColumn<QStringList>("readBackProperties");
2905 QTest::addColumn<QVariantList>("readBackExpectedValues");
2907 QTest::newRow("qobject, register + read + method")
2908 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2911 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2912 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2913 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2919 QTest::newRow("script, register + read")
2920 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2923 << (QStringList() << "scriptTest")
2924 << (QVariantList() << 13)
2930 QTest::newRow("qobject, caching + read")
2931 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2934 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2935 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2941 QTest::newRow("script, caching + read")
2942 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2945 << (QStringList() << "scriptTest")
2946 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2952 QTest::newRow("qobject, writing + readonly constraints")
2953 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2955 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2956 << (QStringList() << "readOnlyProperty" << "writableProperty")
2957 << (QVariantList() << 20 << 50)
2958 << (QStringList() << "firstProperty" << "writableProperty")
2959 << (QVariantList() << 30 << 30)
2960 << (QStringList() << "readOnlyProperty" << "writableProperty")
2961 << (QVariantList() << 20 << 30);
2963 QTest::newRow("script, writing + readonly constraints")
2964 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2966 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2967 << (QStringList() << "readBack" << "unchanged")
2968 << (QVariantList() << 13 << 42)
2969 << (QStringList() << "firstProperty" << "secondProperty")
2970 << (QVariantList() << 30 << 30)
2971 << (QStringList() << "readBack" << "unchanged")
2972 << (QVariantList() << 30 << 42);
2974 QTest::newRow("qobject module API enum values in JS")
2975 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2978 << (QStringList() << "enumValue" << "enumMethod")
2979 << (QVariantList() << 42 << 30)
2985 QTest::newRow("qobject, invalid major version fail")
2986 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2987 << QString("QDeclarativeComponent: Component is not ready")
2996 QTest::newRow("qobject, invalid minor version fail")
2997 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2998 << QString("QDeclarativeComponent: Component is not ready")
3008 void tst_qdeclarativeecmascript::moduleApi()
3010 QFETCH(QUrl, testfile);
3011 QFETCH(QString, errorMessage);
3012 QFETCH(QStringList, warningMessages);
3013 QFETCH(QStringList, readProperties);
3014 QFETCH(QVariantList, readExpectedValues);
3015 QFETCH(QStringList, writeProperties);
3016 QFETCH(QVariantList, writeValues);
3017 QFETCH(QStringList, readBackProperties);
3018 QFETCH(QVariantList, readBackExpectedValues);
3020 QDeclarativeComponent component(&engine, testfile);
3022 if (!errorMessage.isEmpty())
3023 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3025 if (warningMessages.size())
3026 foreach (const QString &warning, warningMessages)
3027 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3029 QObject *object = component.create();
3030 if (!errorMessage.isEmpty()) {
3031 QVERIFY(object == 0);
3033 QVERIFY(object != 0);
3034 for (int i = 0; i < readProperties.size(); ++i)
3035 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3036 for (int i = 0; i < writeProperties.size(); ++i)
3037 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3038 for (int i = 0; i < readBackProperties.size(); ++i)
3039 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3044 void tst_qdeclarativeecmascript::importScripts_data()
3046 QTest::addColumn<QUrl>("testfile");
3047 QTest::addColumn<QString>("errorMessage");
3048 QTest::addColumn<QStringList>("warningMessages");
3049 QTest::addColumn<QStringList>("propertyNames");
3050 QTest::addColumn<QVariantList>("propertyValues");
3052 QTest::newRow("basic functionality")
3053 << TEST_FILE("jsimport/testImport.qml")
3056 << (QStringList() << QLatin1String("importedScriptStringValue")
3057 << QLatin1String("importedScriptFunctionValue")
3058 << QLatin1String("importedModuleAttachedPropertyValue")
3059 << QLatin1String("importedModuleEnumValue"))
3060 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3065 QTest::newRow("import scoping")
3066 << TEST_FILE("jsimport/testImportScoping.qml")
3069 << (QStringList() << QLatin1String("componentError"))
3070 << (QVariantList() << QVariant(5));
3072 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3073 << TEST_FILE("jsimportfail/failOne.qml")
3075 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3076 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3077 << (QVariantList() << QVariant(QString()));
3079 QTest::newRow("javascript imports in an import should be private to the import scope")
3080 << TEST_FILE("jsimportfail/failTwo.qml")
3082 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3083 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3084 << (QVariantList() << QVariant(QString()));
3086 QTest::newRow("module imports in an import should be private to the import scope")
3087 << TEST_FILE("jsimportfail/failThree.qml")
3089 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3090 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3091 << (QVariantList() << QVariant(false));
3093 QTest::newRow("typenames in an import should be private to the import scope")
3094 << TEST_FILE("jsimportfail/failFour.qml")
3096 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3097 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3098 << (QVariantList() << QVariant(0));
3100 QTest::newRow("import with imports has it's own activation scope")
3101 << TEST_FILE("jsimportfail/failFive.qml")
3103 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3104 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3105 << (QStringList() << QLatin1String("componentError"))
3106 << (QVariantList() << QVariant(0));
3108 QTest::newRow("import pragma library script")
3109 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3112 << (QStringList() << QLatin1String("testValue"))
3113 << (QVariantList() << QVariant(31));
3115 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3116 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3119 << (QStringList() << QLatin1String("testValue"))
3120 << (QVariantList() << QVariant(0));
3122 QTest::newRow("import pragma library script which has an import")
3123 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3126 << (QStringList() << QLatin1String("testValue"))
3127 << (QVariantList() << QVariant(55));
3129 QTest::newRow("import pragma library script which has a pragma library import")
3130 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3133 << (QStringList() << QLatin1String("testValue"))
3134 << (QVariantList() << QVariant(18));
3137 void tst_qdeclarativeecmascript::importScripts()
3139 QFETCH(QUrl, testfile);
3140 QFETCH(QString, errorMessage);
3141 QFETCH(QStringList, warningMessages);
3142 QFETCH(QStringList, propertyNames);
3143 QFETCH(QVariantList, propertyValues);
3145 QDeclarativeComponent component(&engine, testfile);
3147 if (!errorMessage.isEmpty())
3148 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3150 if (warningMessages.size())
3151 foreach (const QString &warning, warningMessages)
3152 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3154 QObject *object = component.create();
3155 if (!errorMessage.isEmpty()) {
3156 QVERIFY(object == 0);
3158 QVERIFY(object != 0);
3159 for (int i = 0; i < propertyNames.size(); ++i)
3160 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3165 void tst_qdeclarativeecmascript::scarceResources()
3167 QPixmap origPixmap(100, 100);
3168 origPixmap.fill(Qt::blue);
3170 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3171 ScarceResourceObject *eo = 0;
3172 QObject *object = 0;
3174 // in the following three cases, the instance created from the component
3175 // has a property which is a copy of the scarce resource; hence, the
3176 // resource should NOT be detached prior to deletion of the object instance,
3177 // unless the resource is destroyed explicitly.
3178 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3179 object = component.create();
3180 QVERIFY(object != 0);
3181 QVERIFY(object->property("scarceResourceCopy").isValid());
3182 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3183 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3184 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3185 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3188 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3189 object = componentTwo.create();
3190 QVERIFY(object != 0);
3191 QVERIFY(object->property("scarceResourceCopy").isValid());
3192 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3193 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3194 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3195 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3198 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3199 object = componentThree.create();
3200 QVERIFY(object != 0);
3201 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3202 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3203 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3204 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3207 // in the following three cases, no other copy should exist in memory,
3208 // and so it should be detached (unless explicitly preserved).
3209 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3210 object = componentFour.create();
3211 QVERIFY(object != 0);
3212 QVERIFY(object->property("scarceResourceTest").isValid());
3213 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3214 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3215 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3216 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3219 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3220 object = componentFive.create();
3221 QVERIFY(object != 0);
3222 QVERIFY(object->property("scarceResourceTest").isValid());
3223 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3224 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3225 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3226 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3229 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3230 object = componentSix.create();
3231 QVERIFY(object != 0);
3232 QVERIFY(object->property("scarceResourceTest").isValid());
3233 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3234 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3235 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3236 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3239 // test that scarce resources are handled correctly for imports
3240 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3241 object = componentSeven.create();
3242 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3243 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3246 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3247 object = componentEight.create();
3248 QVERIFY(object != 0);
3249 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3250 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3253 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3254 object = componentNine.create();
3255 QVERIFY(object != 0);
3256 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3257 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3258 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3259 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3260 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3261 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3264 // test that scarce resources are handled properly in signal invocation
3265 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3266 object = componentTen.create();
3267 QVERIFY(object != 0);
3268 QObject *srsc = object->findChild<QObject*>("srsc");
3270 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3271 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3272 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3273 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3274 QMetaObject::invokeMethod(srsc, "testSignal");
3275 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3276 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3277 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3278 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3279 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3280 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3281 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3282 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3283 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3284 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3287 // test that scarce resources are handled properly from js functions in qml files
3288 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3289 object = componentEleven.create();
3290 QVERIFY(object != 0);
3291 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3292 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3293 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3294 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3295 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3296 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3297 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3298 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3299 QMetaObject::invokeMethod(object, "releaseScarceResource");
3300 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3301 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3302 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3303 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3306 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3307 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3308 object = componentTwelve.create();
3309 QVERIFY(object != 0);
3310 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3311 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3312 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3313 QString srp_name = object->property("srp_name").toString();
3314 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3315 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3316 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3317 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3318 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3319 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3320 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3324 void tst_qdeclarativeecmascript::propertyChangeSlots()
3326 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3327 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3328 QObject *object = component.create();
3329 QVERIFY(object != 0);
3332 // ensure that invalid property names fail properly.
3333 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3334 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3335 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3336 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3337 object = e1.create();
3338 QVERIFY(object == 0);
3341 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3342 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3343 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3344 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3345 object = e2.create();
3346 QVERIFY(object == 0);
3349 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3350 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3351 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3352 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3353 object = e3.create();
3354 QVERIFY(object == 0);
3357 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3358 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3359 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3360 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3361 object = e4.create();
3362 QVERIFY(object == 0);
3366 void tst_qdeclarativeecmascript::propertyVar_data()
3368 QTest::addColumn<QUrl>("qmlFile");
3371 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3372 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3373 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3374 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3375 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3376 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3377 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3378 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3379 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3382 void tst_qdeclarativeecmascript::propertyVar()
3384 QFETCH(QUrl, qmlFile);
3386 QDeclarativeComponent component(&engine, qmlFile);
3387 QObject *object = component.create();
3388 QVERIFY(object != 0);
3390 QCOMPARE(object->property("test").toBool(), true);
3395 // Tests that we can write QVariant values to var properties from C++
3396 void tst_qdeclarativeecmascript::propertyVarCpp()
3398 QObject *object = 0;
3400 // ensure that writing to and reading from a var property from cpp works as required.
3401 // Literal values stored in var properties can be read and written as QVariants
3402 // of a specific type, whereas object values are read as QVariantMaps.
3403 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3404 object = component.create();
3405 QVERIFY(object != 0);
3406 // assign int to property var that currently has int assigned
3407 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3408 QCOMPARE(object->property("varBound"), QVariant(15));
3409 QCOMPARE(object->property("intBound"), QVariant(15));
3410 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3411 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3412 // assign string to property var that current has bool assigned
3413 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3414 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3415 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3416 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3417 // now enforce behaviour when accessing JavaScript objects from cpp.
3418 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3422 static void gc(QDeclarativeEngine &engine)
3424 engine.collectGarbage();
3425 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3428 void tst_qdeclarativeecmascript::propertyVarOwnership()
3430 // Referenced JS objects are not collected
3432 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3433 QObject *object = component.create();
3434 QVERIFY(object != 0);
3435 QCOMPARE(object->property("test").toBool(), false);
3436 QMetaObject::invokeMethod(object, "runTest");
3437 QCOMPARE(object->property("test").toBool(), true);
3440 // Referenced JS objects are not collected
3442 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3443 QObject *object = component.create();
3444 QVERIFY(object != 0);
3445 QCOMPARE(object->property("test").toBool(), false);
3446 QMetaObject::invokeMethod(object, "runTest");
3447 QCOMPARE(object->property("test").toBool(), true);
3450 // Qt objects are not collected until they've been dereferenced
3452 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3453 QObject *object = component.create();
3454 QVERIFY(object != 0);
3456 QCOMPARE(object->property("test2").toBool(), false);
3457 QCOMPARE(object->property("test2").toBool(), false);
3459 QMetaObject::invokeMethod(object, "runTest");
3460 QCOMPARE(object->property("test1").toBool(), true);
3462 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3463 QVERIFY(!referencedObject.isNull());
3465 QVERIFY(!referencedObject.isNull());
3467 QMetaObject::invokeMethod(object, "runTest2");
3468 QCOMPARE(object->property("test2").toBool(), true);
3470 QVERIFY(referencedObject.isNull());
3474 // Self reference does not prevent Qt object collection
3476 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3477 QObject *object = component.create();
3478 QVERIFY(object != 0);
3480 QCOMPARE(object->property("test").toBool(), true);
3482 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3483 QVERIFY(!referencedObject.isNull());
3485 QVERIFY(!referencedObject.isNull());
3487 QMetaObject::invokeMethod(object, "runTest");
3489 QVERIFY(referencedObject.isNull());
3495 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3497 // The childObject has a reference to a different QObject. We want to ensure
3498 // that the different item will not be cleaned up until required. IE, the childObject
3499 // has implicit ownership of the constructed QObject.
3500 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3501 QObject *object = component.create();
3502 QVERIFY(object != 0);
3503 QMetaObject::invokeMethod(object, "assignCircular");
3504 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3505 QObject *rootObject = object->property("vp").value<QObject*>();
3506 QVERIFY(rootObject != 0);
3507 QObject *childObject = rootObject->findChild<QObject*>("text");
3508 QVERIFY(childObject != 0);
3509 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3510 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3511 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3512 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3513 QVERIFY(!qobjectGuard.isNull());
3514 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3515 QVERIFY(!qobjectGuard.isNull());
3516 QMetaObject::invokeMethod(object, "deassignCircular");
3517 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3518 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3522 void tst_qdeclarativeecmascript::propertyVarReparent()
3524 // ensure that nothing breaks if we re-parent objects
3525 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3526 QObject *object = component.create();
3527 QVERIFY(object != 0);
3528 QMetaObject::invokeMethod(object, "assignVarProp");
3529 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3530 QObject *rect = object->property("vp").value<QObject*>();
3531 QObject *text = rect->findChild<QObject*>("textOne");
3532 QObject *text2 = rect->findChild<QObject*>("textTwo");
3533 QWeakPointer<QObject> rectGuard(rect);
3534 QWeakPointer<QObject> textGuard(text);
3535 QWeakPointer<QObject> text2Guard(text2);
3536 QVERIFY(!rectGuard.isNull());
3537 QVERIFY(!textGuard.isNull());
3538 QVERIFY(!text2Guard.isNull());
3539 QCOMPARE(text->property("textCanary").toInt(), 11);
3540 QCOMPARE(text2->property("textCanary").toInt(), 12);
3541 // now construct an image which we will reparent.
3542 QMetaObject::invokeMethod(text2, "constructQObject");
3543 QObject *image = text2->property("vp").value<QObject*>();
3544 QWeakPointer<QObject> imageGuard(image);
3545 QVERIFY(!imageGuard.isNull());
3546 QCOMPARE(image->property("imageCanary").toInt(), 13);
3547 // now reparent the "Image" object (currently, it has JS ownership)
3548 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3549 QMetaObject::invokeMethod(text2, "deassignVp");
3550 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3551 QCOMPARE(text->property("textCanary").toInt(), 11);
3552 QCOMPARE(text2->property("textCanary").toInt(), 22);
3553 QVERIFY(!imageGuard.isNull()); // should still be alive.
3554 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3555 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3556 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3557 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3561 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3563 // sometimes reparenting can cause problems
3564 // (eg, if the ctxt is collected, varproperties are no longer available)
3565 // this test ensures that no crash occurs in that situation.
3566 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3567 QObject *object = component.create();
3568 QVERIFY(object != 0);
3569 QMetaObject::invokeMethod(object, "assignVarProp");
3570 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3571 QObject *rect = object->property("vp").value<QObject*>();
3572 QObject *text = rect->findChild<QObject*>("textOne");
3573 QObject *text2 = rect->findChild<QObject*>("textTwo");
3574 QWeakPointer<QObject> rectGuard(rect);
3575 QWeakPointer<QObject> textGuard(text);
3576 QWeakPointer<QObject> text2Guard(text2);
3577 QVERIFY(!rectGuard.isNull());
3578 QVERIFY(!textGuard.isNull());
3579 QVERIFY(!text2Guard.isNull());
3580 QCOMPARE(text->property("textCanary").toInt(), 11);
3581 QCOMPARE(text2->property("textCanary").toInt(), 12);
3582 // now construct an image which we will reparent.
3583 QMetaObject::invokeMethod(text2, "constructQObject");
3584 QObject *image = text2->property("vp").value<QObject*>();
3585 QWeakPointer<QObject> imageGuard(image);
3586 QVERIFY(!imageGuard.isNull());
3587 QCOMPARE(image->property("imageCanary").toInt(), 13);
3588 // now reparent the "Image" object (currently, it has JS ownership)
3589 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3590 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3591 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3592 QVERIFY(!imageGuard.isNull()); // should still be alive.
3593 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3595 QVERIFY(imageGuard.isNull()); // should now be dead.
3598 void tst_qdeclarativeecmascript::propertyVarCircular()
3600 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3601 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3602 QObject *object = component.create();
3603 QVERIFY(object != 0);
3604 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3605 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3606 QCOMPARE(object->property("canaryInt"), QVariant(5));
3607 QVariant canaryResourceVariant = object->property("canaryResource");
3608 QVERIFY(canaryResourceVariant.isValid());
3609 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3610 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3611 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3612 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3613 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3614 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3615 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3616 QCOMPARE(object->property("canaryInt"), QVariant(2));
3617 QCOMPARE(object->property("canaryResource"), QVariant(1));
3618 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3622 void tst_qdeclarativeecmascript::propertyVarCircular2()
3624 // track deletion of JS-owned parent item with Cpp-owned child
3625 // where the child has a var property referencing its parent.
3626 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3627 QObject *object = component.create();
3628 QVERIFY(object != 0);
3629 QMetaObject::invokeMethod(object, "assignCircular");
3630 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3631 QObject *rootObject = object->property("vp").value<QObject*>();
3632 QVERIFY(rootObject != 0);
3633 QObject *childObject = rootObject->findChild<QObject*>("text");
3634 QVERIFY(childObject != 0);
3635 QWeakPointer<QObject> rootObjectTracker(rootObject);
3636 QVERIFY(!rootObjectTracker.isNull());
3637 QWeakPointer<QObject> childObjectTracker(childObject);
3638 QVERIFY(!childObjectTracker.isNull());
3640 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3641 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3642 QMetaObject::invokeMethod(object, "deassignCircular");
3643 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3644 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3645 QVERIFY(childObjectTracker.isNull()); // should have been collected
3649 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3651 *(int*)(parameter) += 1;
3652 qPersistentDispose(object);
3655 void tst_qdeclarativeecmascript::propertyVarInheritance()
3657 int propertyVarWeakRefCallbackCount = 0;
3659 // enforce behaviour regarding element inheritance - ensure handle disposal.
3660 // The particular component under test here has a chain of references.
3661 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3662 QObject *object = component.create();
3663 QVERIFY(object != 0);
3664 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3665 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3666 // we want to be able to track when the varProperties array of the last metaobject is disposed
3667 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3668 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*>();
3669 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3670 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3671 v8::Persistent<v8::Value> icoCanaryHandle;
3672 v8::Persistent<v8::Value> ccoCanaryHandle;
3675 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3676 // public function which can return us a handle to something in the varProperties array.
3677 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3678 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3679 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3680 // as the varproperties array of each vmemo still references the resource.
3681 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3682 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3684 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3686 // now we deassign the var prop, which should trigger collection of item subtrees.
3687 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3688 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3689 // ensure that there are only weak handles to the underlying varProperties array remaining.
3691 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3693 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3694 // to what remains are weak, all varProperties arrays must have been collected.
3697 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3699 int propertyVarWeakRefCallbackCount = 0;
3701 // The particular component under test here does NOT have a chain of references; the
3702 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3703 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3704 QObject *object = component.create();
3705 QVERIFY(object != 0);
3706 QMetaObject::invokeMethod(object, "assignCircular");
3707 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3708 QObject *rootObject = object->property("vp").value<QObject*>();
3709 QVERIFY(rootObject != 0);
3710 QObject *childObject = rootObject->findChild<QObject*>("text");
3711 QVERIFY(childObject != 0);
3712 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3713 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3714 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3717 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3718 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3719 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3721 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3722 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3724 QMetaObject::invokeMethod(object, "deassignCircular");
3725 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3726 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3730 // Ensure that QObject type conversion works on binding assignment
3731 void tst_qdeclarativeecmascript::elementAssign()
3733 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3735 QObject *object = component.create();
3736 QVERIFY(object != 0);
3738 QCOMPARE(object->property("test").toBool(), true);
3744 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3746 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3748 QObject *object = component.create();
3749 QVERIFY(object != 0);
3751 QCOMPARE(object->property("test").toBool(), true);
3757 void tst_qdeclarativeecmascript::objectConversion()
3759 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3761 QObject *object = component.create();
3762 QVERIFY(object != 0);
3764 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3765 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3772 void tst_qdeclarativeecmascript::booleanConversion()
3774 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3776 QObject *object = component.create();
3777 QVERIFY(object != 0);
3779 QCOMPARE(object->property("test_true1").toBool(), true);
3780 QCOMPARE(object->property("test_true2").toBool(), true);
3781 QCOMPARE(object->property("test_true3").toBool(), true);
3782 QCOMPARE(object->property("test_true4").toBool(), true);
3783 QCOMPARE(object->property("test_true5").toBool(), true);
3785 QCOMPARE(object->property("test_false1").toBool(), false);
3786 QCOMPARE(object->property("test_false2").toBool(), false);
3787 QCOMPARE(object->property("test_false3").toBool(), false);
3792 void tst_qdeclarativeecmascript::handleReferenceManagement()
3797 // Linear QObject reference
3798 QDeclarativeEngine hrmEngine;
3799 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3800 QObject *object = component.create();
3801 QVERIFY(object != 0);
3802 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3803 cro->setDtorCount(&dtorCount);
3804 QMetaObject::invokeMethod(object, "createReference");
3806 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3808 hrmEngine.collectGarbage();
3809 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3810 QCOMPARE(dtorCount, 3);
3815 // Circular QObject reference
3816 QDeclarativeEngine hrmEngine;
3817 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3818 QObject *object = component.create();
3819 QVERIFY(object != 0);
3820 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3821 cro->setDtorCount(&dtorCount);
3822 QMetaObject::invokeMethod(object, "circularReference");
3824 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3826 hrmEngine.collectGarbage();
3827 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3828 QCOMPARE(dtorCount, 3);
3833 // Linear handle reference
3834 QDeclarativeEngine hrmEngine;
3835 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3836 QObject *object = component.create();
3837 QVERIFY(object != 0);
3838 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3840 crh->setDtorCount(&dtorCount);
3841 QMetaObject::invokeMethod(object, "createReference");
3842 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3843 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3844 QVERIFY(first != 0);
3845 QVERIFY(second != 0);
3846 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3847 // now we have to reparent second and make second owned by JS.
3848 second->setParent(0);
3849 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3851 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3853 hrmEngine.collectGarbage();
3854 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3855 QCOMPARE(dtorCount, 3);
3860 // Circular handle reference
3861 QDeclarativeEngine hrmEngine;
3862 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3863 QObject *object = component.create();
3864 QVERIFY(object != 0);
3865 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3867 crh->setDtorCount(&dtorCount);
3868 QMetaObject::invokeMethod(object, "circularReference");
3869 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3870 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3871 QVERIFY(first != 0);
3872 QVERIFY(second != 0);
3873 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3874 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3875 // now we have to reparent and change ownership.
3876 first->setParent(0);
3877 second->setParent(0);
3878 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3879 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3881 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3883 hrmEngine.collectGarbage();
3884 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3885 QCOMPARE(dtorCount, 3);
3890 // multiple engine interaction - linear reference
3891 QDeclarativeEngine hrmEngine1;
3892 QDeclarativeEngine hrmEngine2;
3893 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3894 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3895 QObject *object1 = component1.create();
3896 QObject *object2 = component2.create();
3897 QVERIFY(object1 != 0);
3898 QVERIFY(object2 != 0);
3899 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3900 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3903 crh1->setDtorCount(&dtorCount);
3904 crh2->setDtorCount(&dtorCount);
3905 QMetaObject::invokeMethod(object1, "createReference");
3906 QMetaObject::invokeMethod(object2, "createReference");
3907 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3908 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3909 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3910 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3911 QVERIFY(first1 != 0);
3912 QVERIFY(second1 != 0);
3913 QVERIFY(first2 != 0);
3914 QVERIFY(second2 != 0);
3915 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3916 // now we have to reparent second2 and make second2 owned by JS.
3917 second2->setParent(0);
3918 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3920 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3921 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3924 hrmEngine1.collectGarbage();
3925 hrmEngine2.collectGarbage();
3926 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3927 QCOMPARE(dtorCount, 6);
3932 // multiple engine interaction - circular reference
3933 QDeclarativeEngine hrmEngine1;
3934 QDeclarativeEngine hrmEngine2;
3935 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3936 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3937 QObject *object1 = component1.create();
3938 QObject *object2 = component2.create();
3939 QVERIFY(object1 != 0);
3940 QVERIFY(object2 != 0);
3941 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3942 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3945 crh1->setDtorCount(&dtorCount);
3946 crh2->setDtorCount(&dtorCount);
3947 QMetaObject::invokeMethod(object1, "createReference");
3948 QMetaObject::invokeMethod(object2, "createReference");
3949 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3950 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3951 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3952 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3953 QVERIFY(first1 != 0);
3954 QVERIFY(second1 != 0);
3955 QVERIFY(first2 != 0);
3956 QVERIFY(second2 != 0);
3957 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3958 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3959 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3960 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3961 // now we have to reparent and change ownership to JS.
3962 first1->setParent(0);
3963 second1->setParent(0);
3964 first2->setParent(0);
3965 second2->setParent(0);
3966 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3967 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3968 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3969 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3971 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3972 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3975 hrmEngine1.collectGarbage();
3976 hrmEngine2.collectGarbage();
3977 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3978 QCOMPARE(dtorCount, 6);
3983 // multiple engine interaction - linear reference with engine deletion
3984 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3985 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3986 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3987 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3988 QObject *object1 = component1.create();
3989 QObject *object2 = component2.create();
3990 QVERIFY(object1 != 0);
3991 QVERIFY(object2 != 0);
3992 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3993 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3996 crh1->setDtorCount(&dtorCount);
3997 crh2->setDtorCount(&dtorCount);
3998 QMetaObject::invokeMethod(object1, "createReference");
3999 QMetaObject::invokeMethod(object2, "createReference");
4000 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4001 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4002 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4003 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4004 QVERIFY(first1 != 0);
4005 QVERIFY(second1 != 0);
4006 QVERIFY(first2 != 0);
4007 QVERIFY(second2 != 0);
4008 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4009 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4010 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4011 // now we have to reparent and change ownership to JS.
4012 first1->setParent(crh1);
4013 second1->setParent(0);
4014 first2->setParent(0);
4015 second2->setParent(0);
4016 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4017 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4018 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4020 QCOMPARE(dtorCount, 0);
4023 QCOMPARE(dtorCount, 0);
4026 hrmEngine1->collectGarbage();
4027 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4028 QCOMPARE(dtorCount, 6);
4033 void tst_qdeclarativeecmascript::stringArg()
4035 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4036 QObject *object = component.create();
4037 QVERIFY(object != 0);
4038 QMetaObject::invokeMethod(object, "success");
4039 QVERIFY(object->property("returnValue").toBool());
4041 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4042 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4043 QMetaObject::invokeMethod(object, "failure");
4044 QVERIFY(object->property("returnValue").toBool());
4049 void tst_qdeclarativeecmascript::readonlyDeclaration()
4051 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4053 QObject *object = component.create();
4054 QVERIFY(object != 0);
4056 QCOMPARE(object->property("test").toBool(), true);
4061 Q_DECLARE_METATYPE(QList<int>)
4062 Q_DECLARE_METATYPE(QList<qreal>)
4063 Q_DECLARE_METATYPE(QList<bool>)
4064 Q_DECLARE_METATYPE(QList<QString>)
4065 Q_DECLARE_METATYPE(QList<QUrl>)
4066 void tst_qdeclarativeecmascript::sequenceConversionRead()
4069 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4070 QDeclarativeComponent component(&engine, qmlFile);
4071 QObject *object = component.create();
4072 QVERIFY(object != 0);
4073 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4076 QMetaObject::invokeMethod(object, "readSequences");
4077 QList<int> intList; intList << 1 << 2 << 3 << 4;
4078 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4079 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4080 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4081 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4082 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4083 QList<bool> boolList; boolList << true << false << true << false;
4084 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4085 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4086 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4087 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4088 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4089 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4090 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4091 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4092 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4093 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4094 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4096 QMetaObject::invokeMethod(object, "readSequenceElements");
4097 QCOMPARE(object->property("intVal").toInt(), 2);
4098 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4099 QCOMPARE(object->property("boolVal").toBool(), false);
4100 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4101 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4102 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4104 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4105 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4107 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4108 QDeclarativeProperty seqProp(seq, "intListProperty");
4109 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4110 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4111 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4113 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4114 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4120 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4121 QDeclarativeComponent component(&engine, qmlFile);
4122 QObject *object = component.create();
4123 QVERIFY(object != 0);
4124 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4127 // we haven't registered QList<QPoint> as a sequence type.
4128 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4129 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4130 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4131 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4133 QMetaObject::invokeMethod(object, "performTest");
4135 // QList<QPoint> has not been registered as a sequence type.
4136 QCOMPARE(object->property("pointListLength").toInt(), 0);
4137 QVERIFY(!object->property("pointList").isValid());
4138 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4139 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4140 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4146 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4149 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4150 QDeclarativeComponent component(&engine, qmlFile);
4151 QObject *object = component.create();
4152 QVERIFY(object != 0);
4153 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4156 QMetaObject::invokeMethod(object, "writeSequences");
4157 QCOMPARE(object->property("success").toBool(), true);
4159 QMetaObject::invokeMethod(object, "writeSequenceElements");
4160 QCOMPARE(object->property("success").toBool(), true);
4162 QMetaObject::invokeMethod(object, "writeOtherElements");
4163 QCOMPARE(object->property("success").toBool(), true);
4165 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4166 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4172 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4173 QDeclarativeComponent component(&engine, qmlFile);
4174 QObject *object = component.create();
4175 QVERIFY(object != 0);
4176 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4179 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4180 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4181 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4183 QMetaObject::invokeMethod(object, "performTest");
4185 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4186 QCOMPARE(seq->pointListProperty(), pointList);
4192 void tst_qdeclarativeecmascript::sequenceConversionArray()
4194 // ensure that in JS the returned sequences act just like normal JS Arrays.
4195 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4196 QDeclarativeComponent component(&engine, qmlFile);
4197 QObject *object = component.create();
4198 QVERIFY(object != 0);
4199 //QMetaObject::invokeMethod(object, "indexedAccess");
4200 //QVERIFY(object->property("success").toBool());
4201 //QMetaObject::invokeMethod(object, "arrayOperations");
4202 //QVERIFY(object->property("success").toBool());
4203 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4204 QVERIFY(object->property("success").toBool());
4205 //QMetaObject::invokeMethod(object, "testReferenceDeletion");
4206 //QCOMPARE(object->property("referenceDeletion").toBool(), true);
4210 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4212 // ensure that sequence conversion operations work correctly in a worker thread
4213 // and that serialisation between the main and worker thread succeeds.
4214 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4215 QDeclarativeComponent component(&engine, qmlFile);
4216 QObject *object = component.create();
4217 QVERIFY(object != 0);
4219 QMetaObject::invokeMethod(object, "testIntSequence");
4220 QTRY_VERIFY(object->property("finished").toBool());
4221 QVERIFY(object->property("success").toBool());
4223 QMetaObject::invokeMethod(object, "testQrealSequence");
4224 QTRY_VERIFY(object->property("finished").toBool());
4225 QVERIFY(object->property("success").toBool());
4227 QMetaObject::invokeMethod(object, "testBoolSequence");
4228 QTRY_VERIFY(object->property("finished").toBool());
4229 QVERIFY(object->property("success").toBool());
4231 QMetaObject::invokeMethod(object, "testStringSequence");
4232 QTRY_VERIFY(object->property("finished").toBool());
4233 QVERIFY(object->property("success").toBool());
4235 QMetaObject::invokeMethod(object, "testQStringSequence");
4236 QTRY_VERIFY(object->property("finished").toBool());
4237 QVERIFY(object->property("success").toBool());
4239 QMetaObject::invokeMethod(object, "testUrlSequence");
4240 QTRY_VERIFY(object->property("finished").toBool());
4241 QVERIFY(object->property("success").toBool());
4243 QMetaObject::invokeMethod(object, "testVariantSequence");
4244 QTRY_VERIFY(object->property("finished").toBool());
4245 QVERIFY(object->property("success").toBool());
4250 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4253 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4254 QDeclarativeComponent component(&engine, qmlFile);
4255 QObject *object = component.create();
4256 QVERIFY(object != 0);
4257 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4258 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4259 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4260 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4261 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4266 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4267 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4268 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4269 QDeclarativeComponent component(&engine, qmlFile);
4270 QObject *object = component.create();
4271 QVERIFY(object != 0);
4276 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4278 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4279 QDeclarativeComponent component(&engine, qmlFile);
4280 QObject *object = component.create();
4281 QVERIFY(object != 0);
4282 QMetaObject::invokeMethod(object, "testCopySequences");
4283 QCOMPARE(object->property("success").toBool(), true);
4284 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4285 QCOMPARE(object->property("success").toBool(), true);
4286 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4287 QCOMPARE(object->property("success").toBool(), true);
4291 // Test that assigning a null object works
4292 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4293 void tst_qdeclarativeecmascript::nullObjectBinding()
4295 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4297 QObject *object = component.create();
4298 QVERIFY(object != 0);
4300 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4305 // Test that bindings don't evaluate once the engine has been destroyed
4306 void tst_qdeclarativeecmascript::deletedEngine()
4308 QDeclarativeEngine *engine = new QDeclarativeEngine;
4309 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4311 QObject *object = component.create();
4312 QVERIFY(object != 0);
4314 QCOMPARE(object->property("a").toInt(), 39);
4315 object->setProperty("b", QVariant(9));
4316 QCOMPARE(object->property("a").toInt(), 117);
4320 QCOMPARE(object->property("a").toInt(), 117);
4321 object->setProperty("b", QVariant(10));
4322 QCOMPARE(object->property("a").toInt(), 117);
4327 // Test the crashing part of QTBUG-9705
4328 void tst_qdeclarativeecmascript::libraryScriptAssert()
4330 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4332 QObject *object = component.create();
4333 QVERIFY(object != 0);
4338 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4340 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4342 QObject *object = component.create();
4343 QVERIFY(object != 0);
4345 QCOMPARE(object->property("test1").toInt(), 10);
4346 QCOMPARE(object->property("test2").toInt(), 11);
4348 object->setProperty("runTest", true);
4350 QCOMPARE(object->property("test1"), QVariant());
4351 QCOMPARE(object->property("test2"), QVariant());
4357 void tst_qdeclarativeecmascript::qtbug_9792()
4359 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4361 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4363 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4364 QVERIFY(object != 0);
4366 QString message = QString(QLatin1String("Hello world! (%1:%2)")).arg(TEST_FILE("qtbug_9792.qml").toString()).arg(4);
4367 QTest::ignoreMessage(QtDebugMsg, qPrintable(message));
4368 object->basicSignal();
4372 transientErrorsMsgCount = 0;
4373 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4375 object->basicSignal();
4377 qInstallMsgHandler(old);
4379 QCOMPARE(transientErrorsMsgCount, 0);
4384 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4385 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4387 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4389 QObject *o = component.create();
4392 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4393 QVERIFY(nested != 0);
4395 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4398 nested = qvariant_cast<QObject *>(o->property("object"));
4399 QVERIFY(nested == 0);
4401 // If the bug is present, the next line will crash
4405 // Test that we shut down without stupid warnings
4406 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4409 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4411 QObject *o = component.create();
4413 transientErrorsMsgCount = 0;
4414 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4418 qInstallMsgHandler(old);
4420 QCOMPARE(transientErrorsMsgCount, 0);
4425 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4427 QObject *o = component.create();
4429 transientErrorsMsgCount = 0;
4430 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4434 qInstallMsgHandler(old);
4436 QCOMPARE(transientErrorsMsgCount, 0);
4440 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4443 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4445 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4448 QVERIFY(o->objectProperty() != 0);
4450 o->setProperty("runTest", true);
4452 QVERIFY(o->objectProperty() == 0);
4458 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4460 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4463 QVERIFY(o->objectProperty() == 0);
4469 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4471 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4473 QString url = component.url().toString();
4474 QString warning = url + ":4: Unable to assign a function to a property.";
4475 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4477 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4480 QVERIFY(!o->property("a").isValid());
4485 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4487 QFETCH(QString, triggerProperty);
4489 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4490 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4492 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4494 QVERIFY(!o->property("a").isValid());
4496 o->setProperty("aNumber", QVariant(5));
4497 o->setProperty(triggerProperty.toUtf8().constData(), true);
4498 QCOMPARE(o->property("a"), QVariant(50));
4500 o->setProperty("aNumber", QVariant(10));
4501 QCOMPARE(o->property("a"), QVariant(100));
4506 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4508 QTest::addColumn<QString>("triggerProperty");
4510 QTest::newRow("assign to property") << "assignToProperty";
4511 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4513 QTest::newRow("assign to value type") << "assignToValueType";
4515 QTest::newRow("use 'this'") << "assignWithThis";
4516 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4519 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4521 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4522 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4524 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4526 QVERIFY(!o->property("a").isValid());
4528 o->setProperty("assignFuncWithoutReturn", true);
4529 QVERIFY(!o->property("a").isValid());
4531 QString url = component.url().toString();
4532 QString warning = url + ":67: Unable to assign QString to int";
4533 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4534 o->setProperty("assignWrongType", true);
4536 warning = url + ":71: Unable to assign QString to int";
4537 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4538 o->setProperty("assignWrongTypeToValueType", true);
4543 void tst_qdeclarativeecmascript::eval()
4545 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4547 QObject *o = component.create();
4550 QCOMPARE(o->property("test1").toBool(), true);
4551 QCOMPARE(o->property("test2").toBool(), true);
4552 QCOMPARE(o->property("test3").toBool(), true);
4553 QCOMPARE(o->property("test4").toBool(), true);
4554 QCOMPARE(o->property("test5").toBool(), true);
4559 void tst_qdeclarativeecmascript::function()
4561 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4563 QObject *o = component.create();
4566 QCOMPARE(o->property("test1").toBool(), true);
4567 QCOMPARE(o->property("test2").toBool(), true);
4568 QCOMPARE(o->property("test3").toBool(), true);
4573 // Test the "Qt.include" method
4574 void tst_qdeclarativeecmascript::include()
4576 // Non-library relative include
4578 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4579 QObject *o = component.create();
4582 QCOMPARE(o->property("test0").toInt(), 99);
4583 QCOMPARE(o->property("test1").toBool(), true);
4584 QCOMPARE(o->property("test2").toBool(), true);
4585 QCOMPARE(o->property("test2_1").toBool(), true);
4586 QCOMPARE(o->property("test3").toBool(), true);
4587 QCOMPARE(o->property("test3_1").toBool(), true);
4592 // Library relative include
4594 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4595 QObject *o = component.create();
4598 QCOMPARE(o->property("test0").toInt(), 99);
4599 QCOMPARE(o->property("test1").toBool(), true);
4600 QCOMPARE(o->property("test2").toBool(), true);
4601 QCOMPARE(o->property("test2_1").toBool(), true);
4602 QCOMPARE(o->property("test3").toBool(), true);
4603 QCOMPARE(o->property("test3_1").toBool(), true);
4610 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4611 QObject *o = component.create();
4614 QCOMPARE(o->property("test1").toBool(), true);
4615 QCOMPARE(o->property("test2").toBool(), true);
4616 QCOMPARE(o->property("test3").toBool(), true);
4617 QCOMPARE(o->property("test4").toBool(), true);
4618 QCOMPARE(o->property("test5").toBool(), true);
4619 QCOMPARE(o->property("test6").toBool(), true);
4624 // Including file with ".pragma library"
4626 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4627 QObject *o = component.create();
4629 QCOMPARE(o->property("test1").toInt(), 100);
4636 TestHTTPServer server(8111);
4637 QVERIFY(server.isValid());
4638 server.serveDirectory(TESTDATA(""));
4640 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4641 QObject *o = component.create();
4644 QTRY_VERIFY(o->property("done").toBool() == true);
4645 QTRY_VERIFY(o->property("done2").toBool() == true);
4647 QCOMPARE(o->property("test1").toBool(), true);
4648 QCOMPARE(o->property("test2").toBool(), true);
4649 QCOMPARE(o->property("test3").toBool(), true);
4650 QCOMPARE(o->property("test4").toBool(), true);
4651 QCOMPARE(o->property("test5").toBool(), true);
4653 QCOMPARE(o->property("test6").toBool(), true);
4654 QCOMPARE(o->property("test7").toBool(), true);
4655 QCOMPARE(o->property("test8").toBool(), true);
4656 QCOMPARE(o->property("test9").toBool(), true);
4657 QCOMPARE(o->property("test10").toBool(), true);
4664 TestHTTPServer server(8111);
4665 QVERIFY(server.isValid());
4666 server.serveDirectory(TESTDATA(""));
4668 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4669 QObject *o = component.create();
4672 QTRY_VERIFY(o->property("done").toBool() == true);
4674 QCOMPARE(o->property("test1").toBool(), true);
4675 QCOMPARE(o->property("test2").toBool(), true);
4676 QCOMPARE(o->property("test3").toBool(), true);
4682 void tst_qdeclarativeecmascript::signalHandlers()
4684 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4685 QObject *o = component.create();
4688 QVERIFY(o->property("count").toInt() == 0);
4689 QMetaObject::invokeMethod(o, "testSignalCall");
4690 QCOMPARE(o->property("count").toInt(), 1);
4692 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4693 QCOMPARE(o->property("count").toInt(), 1);
4694 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4696 QVERIFY(o->property("funcCount").toInt() == 0);
4697 QMetaObject::invokeMethod(o, "testSignalConnection");
4698 QCOMPARE(o->property("funcCount").toInt(), 1);
4700 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4701 QCOMPARE(o->property("funcCount").toInt(), 2);
4703 QMetaObject::invokeMethod(o, "testSignalDefined");
4704 QCOMPARE(o->property("definedResult").toBool(), true);
4706 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4707 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4712 void tst_qdeclarativeecmascript::qtbug_10696()
4714 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4715 QObject *o = component.create();
4720 void tst_qdeclarativeecmascript::qtbug_11606()
4722 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4723 QObject *o = component.create();
4725 QCOMPARE(o->property("test").toBool(), true);
4729 void tst_qdeclarativeecmascript::qtbug_11600()
4731 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4732 QObject *o = component.create();
4734 QCOMPARE(o->property("test").toBool(), true);
4738 // Reading and writing non-scriptable properties should fail
4739 void tst_qdeclarativeecmascript::nonscriptable()
4741 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4742 QObject *o = component.create();
4744 QCOMPARE(o->property("readOk").toBool(), true);
4745 QCOMPARE(o->property("writeOk").toBool(), true);
4749 // deleteLater() should not be callable from QML
4750 void tst_qdeclarativeecmascript::deleteLater()
4752 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4753 QObject *o = component.create();
4755 QCOMPARE(o->property("test").toBool(), true);
4759 void tst_qdeclarativeecmascript::in()
4761 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4762 QObject *o = component.create();
4764 QCOMPARE(o->property("test1").toBool(), true);
4765 QCOMPARE(o->property("test2").toBool(), true);
4769 void tst_qdeclarativeecmascript::typeOf()
4771 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4772 QObject *o = component.create();
4774 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4775 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4776 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4777 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4778 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4779 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4780 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4781 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4782 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4783 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4788 void tst_qdeclarativeecmascript::sharedAttachedObject()
4790 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4791 QObject *o = component.create();
4793 QCOMPARE(o->property("test1").toBool(), true);
4794 QCOMPARE(o->property("test2").toBool(), true);
4799 void tst_qdeclarativeecmascript::objectName()
4801 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4802 QObject *o = component.create();
4805 QCOMPARE(o->property("test1").toString(), QString("hello"));
4806 QCOMPARE(o->property("test2").toString(), QString("ell"));
4808 o->setObjectName("world");
4810 QCOMPARE(o->property("test1").toString(), QString("world"));
4811 QCOMPARE(o->property("test2").toString(), QString("orl"));
4816 void tst_qdeclarativeecmascript::writeRemovesBinding()
4818 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4819 QObject *o = component.create();
4822 QCOMPARE(o->property("test").toBool(), true);
4827 // Test bindings assigned to alias properties actually assign to the alias' target
4828 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4830 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4831 QObject *o = component.create();
4834 QCOMPARE(o->property("test").toBool(), true);
4839 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4840 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4843 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4844 QObject *o = component.create();
4847 QCOMPARE(o->property("test").toBool(), true);
4853 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4854 QObject *o = component.create();
4857 QCOMPARE(o->property("test").toBool(), true);
4863 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4864 QObject *o = component.create();
4867 QCOMPARE(o->property("test").toBool(), true);
4873 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4874 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4877 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4878 QObject *o = component.create();
4881 QCOMPARE(o->property("test").toBool(), true);
4887 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4888 QObject *o = component.create();
4891 QCOMPARE(o->property("test").toBool(), true);
4897 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4898 QObject *o = component.create();
4901 QCOMPARE(o->property("test").toBool(), true);
4907 // Allow an alais to a composite element
4909 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4911 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4913 QObject *object = component.create();
4914 QVERIFY(object != 0);
4919 void tst_qdeclarativeecmascript::qtbug_20344()
4921 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
4923 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
4924 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
4926 QObject *object = component.create();
4927 QVERIFY(object != 0);
4932 void tst_qdeclarativeecmascript::revisionErrors()
4935 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4936 QString url = component.url().toString();
4938 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4939 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4940 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4942 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4943 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4944 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4945 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4946 QVERIFY(object != 0);
4950 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4951 QString url = component.url().toString();
4953 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4954 // method2, prop2 from MyRevisionedClass not available
4955 // method4, prop4 from MyRevisionedSubclass not available
4956 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4957 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4958 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4959 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4960 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4962 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4963 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4964 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4965 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4966 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4967 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4968 QVERIFY(object != 0);
4972 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4973 QString url = component.url().toString();
4975 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4976 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4977 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4978 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4979 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4980 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4981 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4982 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4983 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4984 QVERIFY(object != 0);
4989 void tst_qdeclarativeecmascript::revision()
4992 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4993 QString url = component.url().toString();
4995 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4996 QVERIFY(object != 0);
5000 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5001 QString url = component.url().toString();
5003 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5004 QVERIFY(object != 0);
5008 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5009 QString url = component.url().toString();
5011 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5012 QVERIFY(object != 0);
5015 // Test that non-root classes can resolve revisioned methods
5017 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5019 QObject *object = component.create();
5020 QVERIFY(object != 0);
5021 QCOMPARE(object->property("test").toReal(), 11.);
5026 void tst_qdeclarativeecmascript::realToInt()
5028 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5029 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5030 QVERIFY(object != 0);
5032 QMetaObject::invokeMethod(object, "test1");
5033 QCOMPARE(object->value(), int(4));
5034 QMetaObject::invokeMethod(object, "test2");
5035 QCOMPARE(object->value(), int(8));
5037 void tst_qdeclarativeecmascript::dynamicString()
5039 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5040 QObject *object = component.create();
5041 QVERIFY(object != 0);
5042 QCOMPARE(object->property("stringProperty").toString(),
5043 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5046 void tst_qdeclarativeecmascript::automaticSemicolon()
5048 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5049 QObject *object = component.create();
5050 QVERIFY(object != 0);
5053 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5054 void tst_qdeclarativeecmascript::doubleEvaluate()
5056 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5057 QObject *object = component.create();
5058 QVERIFY(object != 0);
5059 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5061 QCOMPARE(wc->count(), 1);
5063 wc->setProperty("x", 9);
5065 QCOMPARE(wc->count(), 2);
5070 static QStringList messages;
5071 static void captureMsgHandler(QtMsgType, const char *msg)
5073 messages.append(QLatin1String(msg));
5076 void tst_qdeclarativeecmascript::nonNotifyable()
5078 QV4Compiler::enableV4(false);
5079 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5080 QV4Compiler::enableV4(true);
5082 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5084 QObject *object = component.create();
5085 qInstallMsgHandler(old);
5087 QVERIFY(object != 0);
5089 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5090 component.url().toString() +
5091 QLatin1String(":5 depends on non-NOTIFYable properties:");
5092 QString expected2 = QLatin1String(" ") +
5093 QLatin1String(object->metaObject()->className()) +
5094 QLatin1String("::value");
5096 QCOMPARE(messages.length(), 2);
5097 QCOMPARE(messages.at(0), expected1);
5098 QCOMPARE(messages.at(1), expected2);
5103 void tst_qdeclarativeecmascript::forInLoop()
5105 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5106 QObject *object = component.create();
5107 QVERIFY(object != 0);
5109 QMetaObject::invokeMethod(object, "listProperty");
5111 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5112 QCOMPARE(r.size(), 3);
5113 QCOMPARE(r[0],QLatin1String("0=obj1"));
5114 QCOMPARE(r[1],QLatin1String("1=obj2"));
5115 QCOMPARE(r[2],QLatin1String("2=obj3"));
5117 //TODO: should test for in loop for other objects (such as QObjects) as well.
5122 // An object the binding depends on is deleted while the binding is still running
5123 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5125 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5126 QObject *object = component.create();
5127 QVERIFY(object != 0);
5131 QTEST_MAIN(tst_qdeclarativeecmascript)
5133 #include "tst_qdeclarativeecmascript.moc"