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 QTest::ignoreMessage(QtDebugMsg, "hello world");
1594 QObject *object = qobject_cast<QObject *>(component.create());
1599 void tst_qdeclarativeecmascript::jsObject()
1601 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1602 QObject *object = component.create();
1603 QVERIFY(object != 0);
1605 QCOMPARE(object->property("test").toInt(), 92);
1610 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1613 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1614 QObject *object = component.create();
1615 QVERIFY(object != 0);
1617 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1619 object->setProperty("setUndefined", true);
1621 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1623 object->setProperty("setUndefined", false);
1625 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1630 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1631 QObject *object = component.create();
1632 QVERIFY(object != 0);
1634 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1636 QMetaObject::invokeMethod(object, "doReset");
1638 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1645 void tst_qdeclarativeecmascript::bug1()
1647 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1648 QObject *object = component.create();
1649 QVERIFY(object != 0);
1651 QCOMPARE(object->property("test").toInt(), 14);
1653 object->setProperty("a", 11);
1655 QCOMPARE(object->property("test").toInt(), 3);
1657 object->setProperty("b", true);
1659 QCOMPARE(object->property("test").toInt(), 9);
1664 void tst_qdeclarativeecmascript::bug2()
1666 QDeclarativeComponent component(&engine);
1667 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1669 QObject *object = component.create();
1670 QVERIFY(object != 0);
1675 // Don't crash in createObject when the component has errors.
1676 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1678 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1679 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1680 QVERIFY(object != 0);
1682 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1683 QMetaObject::invokeMethod(object, "dontCrash");
1684 QObject *created = object->objectProperty();
1685 QVERIFY(created == 0);
1690 // ownership transferred to JS, ensure that GC runs the dtor
1691 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1694 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1696 // allow the engine to go out of scope too.
1698 QDeclarativeEngine dcoEngine;
1699 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1700 QObject *object = component.create();
1701 QVERIFY(object != 0);
1702 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1703 QVERIFY(mdcdo != 0);
1704 mdcdo->setDtorCount(&dtorCount);
1706 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1707 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1709 // we do this once manually, but it should be done automatically
1710 // when the engine goes out of scope (since it should gc in dtor)
1711 QMetaObject::invokeMethod(object, "performGc");
1714 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1720 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1721 QCOMPARE(dtorCount, expectedDtorCount);
1725 void tst_qdeclarativeecmascript::regExpBug()
1727 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1728 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1729 QVERIFY(object != 0);
1730 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1734 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1736 QString functionSource = QLatin1String("(function(object) { return ") +
1737 QLatin1String(source) + QLatin1String(" })");
1739 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1742 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1743 if (function.IsEmpty())
1745 v8::Handle<v8::Value> args[] = { o };
1746 function->Call(engine->global(), 1, args);
1747 return tc.HasCaught();
1750 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1751 const char *source, v8::Handle<v8::Value> result)
1753 QString functionSource = QLatin1String("(function(object) { return ") +
1754 QLatin1String(source) + QLatin1String(" })");
1756 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1759 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1760 if (function.IsEmpty())
1762 v8::Handle<v8::Value> args[] = { o };
1764 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1769 return value->StrictEquals(result);
1772 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1775 QString functionSource = QLatin1String("(function(object) { return ") +
1776 QLatin1String(source) + QLatin1String(" })");
1778 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1780 return v8::Handle<v8::Value>();
1781 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1782 if (function.IsEmpty())
1783 return v8::Handle<v8::Value>();
1784 v8::Handle<v8::Value> args[] = { o };
1786 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1789 return v8::Handle<v8::Value>();
1793 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1794 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1795 #define EVALUATE(source) evaluate(engine, object, source)
1797 void tst_qdeclarativeecmascript::callQtInvokables()
1799 MyInvokableObject o;
1801 QDeclarativeEngine qmlengine;
1802 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1804 QV8Engine *engine = ep->v8engine();
1806 v8::HandleScope handle_scope;
1807 v8::Context::Scope scope(engine->context());
1809 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1811 // Non-existent methods
1813 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1814 QCOMPARE(o.error(), false);
1815 QCOMPARE(o.invoked(), -1);
1816 QCOMPARE(o.actuals().count(), 0);
1819 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1820 QCOMPARE(o.error(), false);
1821 QCOMPARE(o.invoked(), -1);
1822 QCOMPARE(o.actuals().count(), 0);
1824 // Insufficient arguments
1826 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1827 QCOMPARE(o.error(), false);
1828 QCOMPARE(o.invoked(), -1);
1829 QCOMPARE(o.actuals().count(), 0);
1832 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1833 QCOMPARE(o.error(), false);
1834 QCOMPARE(o.invoked(), -1);
1835 QCOMPARE(o.actuals().count(), 0);
1837 // Excessive arguments
1839 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1840 QCOMPARE(o.error(), false);
1841 QCOMPARE(o.invoked(), 8);
1842 QCOMPARE(o.actuals().count(), 1);
1843 QCOMPARE(o.actuals().at(0), QVariant(10));
1846 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1847 QCOMPARE(o.error(), false);
1848 QCOMPARE(o.invoked(), 9);
1849 QCOMPARE(o.actuals().count(), 2);
1850 QCOMPARE(o.actuals().at(0), QVariant(10));
1851 QCOMPARE(o.actuals().at(1), QVariant(11));
1853 // Test return types
1855 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1856 QCOMPARE(o.error(), false);
1857 QCOMPARE(o.invoked(), 0);
1858 QCOMPARE(o.actuals().count(), 0);
1861 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1862 QCOMPARE(o.error(), false);
1863 QCOMPARE(o.invoked(), 1);
1864 QCOMPARE(o.actuals().count(), 0);
1867 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1868 QCOMPARE(o.error(), false);
1869 QCOMPARE(o.invoked(), 2);
1870 QCOMPARE(o.actuals().count(), 0);
1874 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1875 QVERIFY(!ret.IsEmpty());
1876 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1877 QCOMPARE(o.error(), false);
1878 QCOMPARE(o.invoked(), 3);
1879 QCOMPARE(o.actuals().count(), 0);
1884 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1885 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1886 QCOMPARE(o.error(), false);
1887 QCOMPARE(o.invoked(), 4);
1888 QCOMPARE(o.actuals().count(), 0);
1892 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1893 QCOMPARE(o.error(), false);
1894 QCOMPARE(o.invoked(), 5);
1895 QCOMPARE(o.actuals().count(), 0);
1899 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1900 QVERIFY(ret->IsString());
1901 QCOMPARE(engine->toString(ret), QString("Hello world"));
1902 QCOMPARE(o.error(), false);
1903 QCOMPARE(o.invoked(), 6);
1904 QCOMPARE(o.actuals().count(), 0);
1908 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1909 QCOMPARE(o.error(), false);
1910 QCOMPARE(o.invoked(), 7);
1911 QCOMPARE(o.actuals().count(), 0);
1915 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1916 QCOMPARE(o.error(), false);
1917 QCOMPARE(o.invoked(), 8);
1918 QCOMPARE(o.actuals().count(), 1);
1919 QCOMPARE(o.actuals().at(0), QVariant(94));
1922 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1923 QCOMPARE(o.error(), false);
1924 QCOMPARE(o.invoked(), 8);
1925 QCOMPARE(o.actuals().count(), 1);
1926 QCOMPARE(o.actuals().at(0), QVariant(94));
1929 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1930 QCOMPARE(o.error(), false);
1931 QCOMPARE(o.invoked(), 8);
1932 QCOMPARE(o.actuals().count(), 1);
1933 QCOMPARE(o.actuals().at(0), QVariant(0));
1936 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1937 QCOMPARE(o.error(), false);
1938 QCOMPARE(o.invoked(), 8);
1939 QCOMPARE(o.actuals().count(), 1);
1940 QCOMPARE(o.actuals().at(0), QVariant(0));
1943 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1944 QCOMPARE(o.error(), false);
1945 QCOMPARE(o.invoked(), 8);
1946 QCOMPARE(o.actuals().count(), 1);
1947 QCOMPARE(o.actuals().at(0), QVariant(0));
1950 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1951 QCOMPARE(o.error(), false);
1952 QCOMPARE(o.invoked(), 8);
1953 QCOMPARE(o.actuals().count(), 1);
1954 QCOMPARE(o.actuals().at(0), QVariant(0));
1957 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1958 QCOMPARE(o.error(), false);
1959 QCOMPARE(o.invoked(), 9);
1960 QCOMPARE(o.actuals().count(), 2);
1961 QCOMPARE(o.actuals().at(0), QVariant(122));
1962 QCOMPARE(o.actuals().at(1), QVariant(9));
1965 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1966 QCOMPARE(o.error(), false);
1967 QCOMPARE(o.invoked(), 10);
1968 QCOMPARE(o.actuals().count(), 1);
1969 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1972 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1973 QCOMPARE(o.error(), false);
1974 QCOMPARE(o.invoked(), 10);
1975 QCOMPARE(o.actuals().count(), 1);
1976 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1979 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1980 QCOMPARE(o.error(), false);
1981 QCOMPARE(o.invoked(), 10);
1982 QCOMPARE(o.actuals().count(), 1);
1983 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1986 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1987 QCOMPARE(o.error(), false);
1988 QCOMPARE(o.invoked(), 10);
1989 QCOMPARE(o.actuals().count(), 1);
1990 QCOMPARE(o.actuals().at(0), QVariant(0));
1993 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1994 QCOMPARE(o.error(), false);
1995 QCOMPARE(o.invoked(), 10);
1996 QCOMPARE(o.actuals().count(), 1);
1997 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2000 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2001 QCOMPARE(o.error(), false);
2002 QCOMPARE(o.invoked(), 10);
2003 QCOMPARE(o.actuals().count(), 1);
2004 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2007 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2008 QCOMPARE(o.error(), false);
2009 QCOMPARE(o.invoked(), 11);
2010 QCOMPARE(o.actuals().count(), 1);
2011 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2014 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2015 QCOMPARE(o.error(), false);
2016 QCOMPARE(o.invoked(), 11);
2017 QCOMPARE(o.actuals().count(), 1);
2018 QCOMPARE(o.actuals().at(0), QVariant("19"));
2022 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2023 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2024 QCOMPARE(o.error(), false);
2025 QCOMPARE(o.invoked(), 11);
2026 QCOMPARE(o.actuals().count(), 1);
2027 QCOMPARE(o.actuals().at(0), QVariant(expected));
2031 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2032 QCOMPARE(o.error(), false);
2033 QCOMPARE(o.invoked(), 11);
2034 QCOMPARE(o.actuals().count(), 1);
2035 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2038 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2039 QCOMPARE(o.error(), false);
2040 QCOMPARE(o.invoked(), 11);
2041 QCOMPARE(o.actuals().count(), 1);
2042 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2045 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2046 QCOMPARE(o.error(), false);
2047 QCOMPARE(o.invoked(), 12);
2048 QCOMPARE(o.actuals().count(), 1);
2049 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2052 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2053 QCOMPARE(o.error(), false);
2054 QCOMPARE(o.invoked(), 12);
2055 QCOMPARE(o.actuals().count(), 1);
2056 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2059 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2060 QCOMPARE(o.error(), false);
2061 QCOMPARE(o.invoked(), 12);
2062 QCOMPARE(o.actuals().count(), 1);
2063 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2066 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2067 QCOMPARE(o.error(), false);
2068 QCOMPARE(o.invoked(), 12);
2069 QCOMPARE(o.actuals().count(), 1);
2070 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2073 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2074 QCOMPARE(o.error(), false);
2075 QCOMPARE(o.invoked(), 12);
2076 QCOMPARE(o.actuals().count(), 1);
2077 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2080 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2081 QCOMPARE(o.error(), false);
2082 QCOMPARE(o.invoked(), 12);
2083 QCOMPARE(o.actuals().count(), 1);
2084 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2087 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2088 QCOMPARE(o.error(), false);
2089 QCOMPARE(o.invoked(), 13);
2090 QCOMPARE(o.actuals().count(), 1);
2091 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2094 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2095 QCOMPARE(o.error(), false);
2096 QCOMPARE(o.invoked(), 13);
2097 QCOMPARE(o.actuals().count(), 1);
2098 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2101 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2102 QCOMPARE(o.error(), false);
2103 QCOMPARE(o.invoked(), 13);
2104 QCOMPARE(o.actuals().count(), 1);
2105 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2108 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2109 QCOMPARE(o.error(), false);
2110 QCOMPARE(o.invoked(), 13);
2111 QCOMPARE(o.actuals().count(), 1);
2112 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2115 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2116 QCOMPARE(o.error(), false);
2117 QCOMPARE(o.invoked(), 13);
2118 QCOMPARE(o.actuals().count(), 1);
2119 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2122 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2123 QCOMPARE(o.error(), false);
2124 QCOMPARE(o.invoked(), 14);
2125 QCOMPARE(o.actuals().count(), 1);
2126 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2129 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2130 QCOMPARE(o.error(), false);
2131 QCOMPARE(o.invoked(), 14);
2132 QCOMPARE(o.actuals().count(), 1);
2133 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2136 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2137 QCOMPARE(o.error(), false);
2138 QCOMPARE(o.invoked(), 14);
2139 QCOMPARE(o.actuals().count(), 1);
2140 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2143 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2144 QCOMPARE(o.error(), false);
2145 QCOMPARE(o.invoked(), 14);
2146 QCOMPARE(o.actuals().count(), 1);
2147 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2150 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2151 QCOMPARE(o.error(), false);
2152 QCOMPARE(o.invoked(), 15);
2153 QCOMPARE(o.actuals().count(), 2);
2154 QCOMPARE(o.actuals().at(0), QVariant(4));
2155 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2158 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2159 QCOMPARE(o.error(), false);
2160 QCOMPARE(o.invoked(), 15);
2161 QCOMPARE(o.actuals().count(), 2);
2162 QCOMPARE(o.actuals().at(0), QVariant(8));
2163 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2166 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2167 QCOMPARE(o.error(), false);
2168 QCOMPARE(o.invoked(), 15);
2169 QCOMPARE(o.actuals().count(), 2);
2170 QCOMPARE(o.actuals().at(0), QVariant(3));
2171 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2174 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2175 QCOMPARE(o.error(), false);
2176 QCOMPARE(o.invoked(), 15);
2177 QCOMPARE(o.actuals().count(), 2);
2178 QCOMPARE(o.actuals().at(0), QVariant(44));
2179 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2182 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2183 QCOMPARE(o.error(), false);
2184 QCOMPARE(o.invoked(), -1);
2185 QCOMPARE(o.actuals().count(), 0);
2188 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2189 QCOMPARE(o.error(), false);
2190 QCOMPARE(o.invoked(), 16);
2191 QCOMPARE(o.actuals().count(), 1);
2192 QCOMPARE(o.actuals().at(0), QVariant(10));
2195 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2196 QCOMPARE(o.error(), false);
2197 QCOMPARE(o.invoked(), 17);
2198 QCOMPARE(o.actuals().count(), 2);
2199 QCOMPARE(o.actuals().at(0), QVariant(10));
2200 QCOMPARE(o.actuals().at(1), QVariant(11));
2203 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2204 QCOMPARE(o.error(), false);
2205 QCOMPARE(o.invoked(), 18);
2206 QCOMPARE(o.actuals().count(), 1);
2207 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2210 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2211 QCOMPARE(o.error(), false);
2212 QCOMPARE(o.invoked(), 19);
2213 QCOMPARE(o.actuals().count(), 1);
2214 QCOMPARE(o.actuals().at(0), QVariant(9));
2217 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2218 QCOMPARE(o.error(), false);
2219 QCOMPARE(o.invoked(), 20);
2220 QCOMPARE(o.actuals().count(), 2);
2221 QCOMPARE(o.actuals().at(0), QVariant(10));
2222 QCOMPARE(o.actuals().at(1), QVariant(19));
2225 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2226 QCOMPARE(o.error(), false);
2227 QCOMPARE(o.invoked(), 20);
2228 QCOMPARE(o.actuals().count(), 2);
2229 QCOMPARE(o.actuals().at(0), QVariant(10));
2230 QCOMPARE(o.actuals().at(1), QVariant(13));
2233 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2234 QCOMPARE(o.error(), false);
2235 QCOMPARE(o.invoked(), -3);
2236 QCOMPARE(o.actuals().count(), 1);
2237 QCOMPARE(o.actuals().at(0), QVariant(9));
2240 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2241 QCOMPARE(o.error(), false);
2242 QCOMPARE(o.invoked(), 21);
2243 QCOMPARE(o.actuals().count(), 2);
2244 QCOMPARE(o.actuals().at(0), QVariant(9));
2245 QCOMPARE(o.actuals().at(1), QVariant());
2248 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2249 QCOMPARE(o.error(), false);
2250 QCOMPARE(o.invoked(), 21);
2251 QCOMPARE(o.actuals().count(), 2);
2252 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2253 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2256 // QTBUG-13047 (check that you can pass registered object types as args)
2257 void tst_qdeclarativeecmascript::invokableObjectArg()
2259 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2261 QObject *o = component.create();
2263 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2265 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2270 // QTBUG-13047 (check that you can return registered object types from methods)
2271 void tst_qdeclarativeecmascript::invokableObjectRet()
2273 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2275 QObject *o = component.create();
2277 QCOMPARE(o->property("test").toBool(), true);
2282 void tst_qdeclarativeecmascript::listToVariant()
2284 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2286 MyQmlContainer container;
2288 QDeclarativeContext context(engine.rootContext());
2289 context.setContextObject(&container);
2291 QObject *object = component.create(&context);
2292 QVERIFY(object != 0);
2294 QVariant v = object->property("test");
2295 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2296 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2302 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2303 void tst_qdeclarativeecmascript::listAssignment()
2305 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2306 QObject *obj = component.create();
2307 QCOMPARE(obj->property("list1length").toInt(), 2);
2308 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2309 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2310 QCOMPARE(list1.count(&list1), list2.count(&list2));
2311 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2312 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2317 void tst_qdeclarativeecmascript::multiEngineObject()
2320 obj.setStringProperty("Howdy planet");
2322 QDeclarativeEngine e1;
2323 e1.rootContext()->setContextProperty("thing", &obj);
2324 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2326 QDeclarativeEngine e2;
2327 e2.rootContext()->setContextProperty("thing", &obj);
2328 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2330 QObject *o1 = c1.create();
2331 QObject *o2 = c2.create();
2333 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2334 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2340 // Test that references to QObjects are cleanup when the object is destroyed
2341 void tst_qdeclarativeecmascript::deletedObject()
2343 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2345 QObject *object = component.create();
2347 QCOMPARE(object->property("test1").toBool(), true);
2348 QCOMPARE(object->property("test2").toBool(), true);
2349 QCOMPARE(object->property("test3").toBool(), true);
2350 QCOMPARE(object->property("test4").toBool(), true);
2355 void tst_qdeclarativeecmascript::attachedPropertyScope()
2357 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2359 QObject *object = component.create();
2360 QVERIFY(object != 0);
2362 MyQmlAttachedObject *attached =
2363 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2364 QVERIFY(attached != 0);
2366 QCOMPARE(object->property("value2").toInt(), 0);
2368 attached->emitMySignal();
2370 QCOMPARE(object->property("value2").toInt(), 9);
2375 void tst_qdeclarativeecmascript::scriptConnect()
2378 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2380 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2381 QVERIFY(object != 0);
2383 QCOMPARE(object->property("test").toBool(), false);
2384 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2385 QCOMPARE(object->property("test").toBool(), true);
2391 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2393 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2394 QVERIFY(object != 0);
2396 QCOMPARE(object->property("test").toBool(), false);
2397 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2398 QCOMPARE(object->property("test").toBool(), true);
2404 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2406 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2407 QVERIFY(object != 0);
2409 QCOMPARE(object->property("test").toBool(), false);
2410 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2411 QCOMPARE(object->property("test").toBool(), true);
2417 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2419 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2420 QVERIFY(object != 0);
2422 QCOMPARE(object->methodCalled(), false);
2423 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2424 QCOMPARE(object->methodCalled(), true);
2430 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2432 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2433 QVERIFY(object != 0);
2435 QCOMPARE(object->methodCalled(), false);
2436 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2437 QCOMPARE(object->methodCalled(), true);
2443 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2445 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2446 QVERIFY(object != 0);
2448 QCOMPARE(object->property("test").toInt(), 0);
2449 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2450 QCOMPARE(object->property("test").toInt(), 2);
2456 void tst_qdeclarativeecmascript::scriptDisconnect()
2459 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2461 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2462 QVERIFY(object != 0);
2464 QCOMPARE(object->property("test").toInt(), 0);
2465 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2466 QCOMPARE(object->property("test").toInt(), 1);
2467 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2468 QCOMPARE(object->property("test").toInt(), 2);
2469 emit object->basicSignal();
2470 QCOMPARE(object->property("test").toInt(), 2);
2471 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2472 QCOMPARE(object->property("test").toInt(), 2);
2478 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2480 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2481 QVERIFY(object != 0);
2483 QCOMPARE(object->property("test").toInt(), 0);
2484 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2485 QCOMPARE(object->property("test").toInt(), 1);
2486 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2487 QCOMPARE(object->property("test").toInt(), 2);
2488 emit object->basicSignal();
2489 QCOMPARE(object->property("test").toInt(), 2);
2490 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2491 QCOMPARE(object->property("test").toInt(), 2);
2497 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2499 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2500 QVERIFY(object != 0);
2502 QCOMPARE(object->property("test").toInt(), 0);
2503 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2504 QCOMPARE(object->property("test").toInt(), 1);
2505 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2506 QCOMPARE(object->property("test").toInt(), 2);
2507 emit object->basicSignal();
2508 QCOMPARE(object->property("test").toInt(), 2);
2509 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2510 QCOMPARE(object->property("test").toInt(), 3);
2515 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2517 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2518 QVERIFY(object != 0);
2520 QCOMPARE(object->property("test").toInt(), 0);
2521 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2522 QCOMPARE(object->property("test").toInt(), 1);
2523 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2524 QCOMPARE(object->property("test").toInt(), 2);
2525 emit object->basicSignal();
2526 QCOMPARE(object->property("test").toInt(), 2);
2527 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2528 QCOMPARE(object->property("test").toInt(), 3);
2534 class OwnershipObject : public QObject
2538 OwnershipObject() { object = new QObject; }
2540 QPointer<QObject> object;
2543 QObject *getObject() { return object; }
2546 void tst_qdeclarativeecmascript::ownership()
2548 OwnershipObject own;
2549 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2550 context->setContextObject(&own);
2553 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2555 QVERIFY(own.object != 0);
2557 QObject *object = component.create(context);
2559 engine.collectGarbage();
2561 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2563 QVERIFY(own.object == 0);
2568 own.object = new QObject(&own);
2571 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2573 QVERIFY(own.object != 0);
2575 QObject *object = component.create(context);
2577 engine.collectGarbage();
2579 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2581 QVERIFY(own.object != 0);
2589 class CppOwnershipReturnValue : public QObject
2593 CppOwnershipReturnValue() : value(0) {}
2594 ~CppOwnershipReturnValue() { delete value; }
2596 Q_INVOKABLE QObject *create() {
2597 value = new QObject;
2598 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2602 Q_INVOKABLE MyQmlObject *createQmlObject() {
2603 MyQmlObject *rv = new MyQmlObject;
2608 QPointer<QObject> value;
2612 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2613 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2615 CppOwnershipReturnValue source;
2618 QDeclarativeEngine engine;
2619 engine.rootContext()->setContextProperty("source", &source);
2621 QVERIFY(source.value == 0);
2623 QDeclarativeComponent component(&engine);
2624 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2626 QObject *object = component.create();
2628 QVERIFY(object != 0);
2629 QVERIFY(source.value != 0);
2634 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2636 QVERIFY(source.value != 0);
2640 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2642 CppOwnershipReturnValue source;
2645 QDeclarativeEngine engine;
2646 engine.rootContext()->setContextProperty("source", &source);
2648 QVERIFY(source.value == 0);
2650 QDeclarativeComponent component(&engine);
2651 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2653 QObject *object = component.create();
2655 QVERIFY(object != 0);
2656 QVERIFY(source.value != 0);
2661 engine.collectGarbage();
2662 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2664 QVERIFY(source.value == 0);
2667 class QListQObjectMethodsObject : public QObject
2671 QListQObjectMethodsObject() {
2672 m_objects.append(new MyQmlObject());
2673 m_objects.append(new MyQmlObject());
2676 ~QListQObjectMethodsObject() {
2677 qDeleteAll(m_objects);
2681 QList<QObject *> getObjects() { return m_objects; }
2684 QList<QObject *> m_objects;
2687 // Tests that returning a QList<QObject*> from a method works
2688 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2690 QListQObjectMethodsObject obj;
2691 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2692 context->setContextObject(&obj);
2694 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2696 QObject *object = component.create(context);
2698 QCOMPARE(object->property("test").toInt(), 2);
2699 QCOMPARE(object->property("test2").toBool(), true);
2706 void tst_qdeclarativeecmascript::strictlyEquals()
2708 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2710 QObject *object = component.create();
2711 QVERIFY(object != 0);
2713 QCOMPARE(object->property("test1").toBool(), true);
2714 QCOMPARE(object->property("test2").toBool(), true);
2715 QCOMPARE(object->property("test3").toBool(), true);
2716 QCOMPARE(object->property("test4").toBool(), true);
2717 QCOMPARE(object->property("test5").toBool(), true);
2718 QCOMPARE(object->property("test6").toBool(), true);
2719 QCOMPARE(object->property("test7").toBool(), true);
2720 QCOMPARE(object->property("test8").toBool(), true);
2725 void tst_qdeclarativeecmascript::compiled()
2727 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2729 QObject *object = component.create();
2730 QVERIFY(object != 0);
2732 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2733 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2734 QCOMPARE(object->property("test3").toBool(), true);
2735 QCOMPARE(object->property("test4").toBool(), false);
2736 QCOMPARE(object->property("test5").toBool(), false);
2737 QCOMPARE(object->property("test6").toBool(), true);
2739 QCOMPARE(object->property("test7").toInt(), 185);
2740 QCOMPARE(object->property("test8").toInt(), 167);
2741 QCOMPARE(object->property("test9").toBool(), true);
2742 QCOMPARE(object->property("test10").toBool(), false);
2743 QCOMPARE(object->property("test11").toBool(), false);
2744 QCOMPARE(object->property("test12").toBool(), true);
2746 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2747 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2748 QCOMPARE(object->property("test15").toBool(), false);
2749 QCOMPARE(object->property("test16").toBool(), true);
2751 QCOMPARE(object->property("test17").toInt(), 5);
2752 QCOMPARE(object->property("test18").toReal(), qreal(176));
2753 QCOMPARE(object->property("test19").toInt(), 7);
2754 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2755 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2756 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2757 QCOMPARE(object->property("test23").toBool(), true);
2758 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2759 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2764 // Test that numbers assigned in bindings as strings work consistently
2765 void tst_qdeclarativeecmascript::numberAssignment()
2767 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2769 QObject *object = component.create();
2770 QVERIFY(object != 0);
2772 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2773 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2774 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2775 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2776 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2778 QCOMPARE(object->property("test5"), QVariant((int)7));
2779 QCOMPARE(object->property("test6"), QVariant((int)7));
2780 QCOMPARE(object->property("test7"), QVariant((int)6));
2781 QCOMPARE(object->property("test8"), QVariant((int)6));
2783 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2784 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2785 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2786 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2791 void tst_qdeclarativeecmascript::propertySplicing()
2793 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2795 QObject *object = component.create();
2796 QVERIFY(object != 0);
2798 QCOMPARE(object->property("test").toBool(), true);
2804 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2806 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2808 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2809 QVERIFY(object != 0);
2811 MyQmlObject::MyType type;
2812 type.value = 0x8971123;
2813 emit object->signalWithUnknownType(type);
2815 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2817 QCOMPARE(result.value, type.value);
2823 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2825 QTest::addColumn<QString>("expression");
2826 QTest::addColumn<QString>("compare");
2828 QString compareStrict("(function(a, b) { return a === b; })");
2829 QTest::newRow("true") << "true" << compareStrict;
2830 QTest::newRow("undefined") << "undefined" << compareStrict;
2831 QTest::newRow("null") << "null" << compareStrict;
2832 QTest::newRow("123") << "123" << compareStrict;
2833 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2835 QString comparePropertiesStrict(
2837 " if (typeof b != 'object')"
2839 " var props = Object.getOwnPropertyNames(b);"
2840 " for (var i = 0; i < props.length; ++i) {"
2841 " var p = props[i];"
2842 " return arguments.callee(a[p], b[p]);"
2845 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2846 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2849 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2851 QFETCH(QString, expression);
2852 QFETCH(QString, compare);
2854 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2855 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2856 QVERIFY(object != 0);
2858 QJSValue value = engine.evaluate(expression);
2859 QVERIFY(!engine.hasUncaughtException());
2860 object->setProperty("expression", expression);
2861 object->setProperty("compare", compare);
2862 object->setProperty("pass", false);
2864 emit object->signalWithVariant(QVariant::fromValue(value));
2865 QVERIFY(object->property("pass").toBool());
2868 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2870 signalWithJSValueInVariant_data();
2873 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2875 QFETCH(QString, expression);
2876 QFETCH(QString, compare);
2878 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2879 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2880 QVERIFY(object != 0);
2883 QJSValue value = engine2.evaluate(expression);
2884 QVERIFY(!engine2.hasUncaughtException());
2885 object->setProperty("expression", expression);
2886 object->setProperty("compare", compare);
2887 object->setProperty("pass", false);
2889 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2890 emit object->signalWithVariant(QVariant::fromValue(value));
2891 QVERIFY(!object->property("pass").toBool());
2894 void tst_qdeclarativeecmascript::moduleApi_data()
2896 QTest::addColumn<QUrl>("testfile");
2897 QTest::addColumn<QString>("errorMessage");
2898 QTest::addColumn<QStringList>("warningMessages");
2899 QTest::addColumn<QStringList>("readProperties");
2900 QTest::addColumn<QVariantList>("readExpectedValues");
2901 QTest::addColumn<QStringList>("writeProperties");
2902 QTest::addColumn<QVariantList>("writeValues");
2903 QTest::addColumn<QStringList>("readBackProperties");
2904 QTest::addColumn<QVariantList>("readBackExpectedValues");
2906 QTest::newRow("qobject, register + read + method")
2907 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2910 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2911 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2912 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2918 QTest::newRow("script, register + read")
2919 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2922 << (QStringList() << "scriptTest")
2923 << (QVariantList() << 13)
2929 QTest::newRow("qobject, caching + read")
2930 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2933 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2934 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2940 QTest::newRow("script, caching + read")
2941 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2944 << (QStringList() << "scriptTest")
2945 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2951 QTest::newRow("qobject, writing + readonly constraints")
2952 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2954 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2955 << (QStringList() << "readOnlyProperty" << "writableProperty")
2956 << (QVariantList() << 20 << 50)
2957 << (QStringList() << "firstProperty" << "writableProperty")
2958 << (QVariantList() << 30 << 30)
2959 << (QStringList() << "readOnlyProperty" << "writableProperty")
2960 << (QVariantList() << 20 << 30);
2962 QTest::newRow("script, writing + readonly constraints")
2963 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2965 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2966 << (QStringList() << "readBack" << "unchanged")
2967 << (QVariantList() << 13 << 42)
2968 << (QStringList() << "firstProperty" << "secondProperty")
2969 << (QVariantList() << 30 << 30)
2970 << (QStringList() << "readBack" << "unchanged")
2971 << (QVariantList() << 30 << 42);
2973 QTest::newRow("qobject module API enum values in JS")
2974 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2977 << (QStringList() << "enumValue" << "enumMethod")
2978 << (QVariantList() << 42 << 30)
2984 QTest::newRow("qobject, invalid major version fail")
2985 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2986 << QString("QDeclarativeComponent: Component is not ready")
2995 QTest::newRow("qobject, invalid minor version fail")
2996 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2997 << QString("QDeclarativeComponent: Component is not ready")
3007 void tst_qdeclarativeecmascript::moduleApi()
3009 QFETCH(QUrl, testfile);
3010 QFETCH(QString, errorMessage);
3011 QFETCH(QStringList, warningMessages);
3012 QFETCH(QStringList, readProperties);
3013 QFETCH(QVariantList, readExpectedValues);
3014 QFETCH(QStringList, writeProperties);
3015 QFETCH(QVariantList, writeValues);
3016 QFETCH(QStringList, readBackProperties);
3017 QFETCH(QVariantList, readBackExpectedValues);
3019 QDeclarativeComponent component(&engine, testfile);
3021 if (!errorMessage.isEmpty())
3022 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3024 if (warningMessages.size())
3025 foreach (const QString &warning, warningMessages)
3026 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3028 QObject *object = component.create();
3029 if (!errorMessage.isEmpty()) {
3030 QVERIFY(object == 0);
3032 QVERIFY(object != 0);
3033 for (int i = 0; i < readProperties.size(); ++i)
3034 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3035 for (int i = 0; i < writeProperties.size(); ++i)
3036 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3037 for (int i = 0; i < readBackProperties.size(); ++i)
3038 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3043 void tst_qdeclarativeecmascript::importScripts_data()
3045 QTest::addColumn<QUrl>("testfile");
3046 QTest::addColumn<QString>("errorMessage");
3047 QTest::addColumn<QStringList>("warningMessages");
3048 QTest::addColumn<QStringList>("propertyNames");
3049 QTest::addColumn<QVariantList>("propertyValues");
3051 QTest::newRow("basic functionality")
3052 << TEST_FILE("jsimport/testImport.qml")
3055 << (QStringList() << QLatin1String("importedScriptStringValue")
3056 << QLatin1String("importedScriptFunctionValue")
3057 << QLatin1String("importedModuleAttachedPropertyValue")
3058 << QLatin1String("importedModuleEnumValue"))
3059 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3064 QTest::newRow("import scoping")
3065 << TEST_FILE("jsimport/testImportScoping.qml")
3068 << (QStringList() << QLatin1String("componentError"))
3069 << (QVariantList() << QVariant(5));
3071 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3072 << TEST_FILE("jsimportfail/failOne.qml")
3074 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3075 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3076 << (QVariantList() << QVariant(QString()));
3078 QTest::newRow("javascript imports in an import should be private to the import scope")
3079 << TEST_FILE("jsimportfail/failTwo.qml")
3081 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3082 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3083 << (QVariantList() << QVariant(QString()));
3085 QTest::newRow("module imports in an import should be private to the import scope")
3086 << TEST_FILE("jsimportfail/failThree.qml")
3088 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3089 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3090 << (QVariantList() << QVariant(false));
3092 QTest::newRow("typenames in an import should be private to the import scope")
3093 << TEST_FILE("jsimportfail/failFour.qml")
3095 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3096 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3097 << (QVariantList() << QVariant(0));
3099 QTest::newRow("import with imports has it's own activation scope")
3100 << TEST_FILE("jsimportfail/failFive.qml")
3102 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3103 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3104 << (QStringList() << QLatin1String("componentError"))
3105 << (QVariantList() << QVariant(0));
3107 QTest::newRow("import pragma library script")
3108 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3111 << (QStringList() << QLatin1String("testValue"))
3112 << (QVariantList() << QVariant(31));
3114 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3115 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3118 << (QStringList() << QLatin1String("testValue"))
3119 << (QVariantList() << QVariant(0));
3121 QTest::newRow("import pragma library script which has an import")
3122 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3125 << (QStringList() << QLatin1String("testValue"))
3126 << (QVariantList() << QVariant(55));
3128 QTest::newRow("import pragma library script which has a pragma library import")
3129 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3132 << (QStringList() << QLatin1String("testValue"))
3133 << (QVariantList() << QVariant(18));
3136 void tst_qdeclarativeecmascript::importScripts()
3138 QFETCH(QUrl, testfile);
3139 QFETCH(QString, errorMessage);
3140 QFETCH(QStringList, warningMessages);
3141 QFETCH(QStringList, propertyNames);
3142 QFETCH(QVariantList, propertyValues);
3144 QDeclarativeComponent component(&engine, testfile);
3146 if (!errorMessage.isEmpty())
3147 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3149 if (warningMessages.size())
3150 foreach (const QString &warning, warningMessages)
3151 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3153 QObject *object = component.create();
3154 if (!errorMessage.isEmpty()) {
3155 QVERIFY(object == 0);
3157 QVERIFY(object != 0);
3158 for (int i = 0; i < propertyNames.size(); ++i)
3159 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3164 void tst_qdeclarativeecmascript::scarceResources()
3166 QPixmap origPixmap(100, 100);
3167 origPixmap.fill(Qt::blue);
3169 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3170 ScarceResourceObject *eo = 0;
3171 QObject *object = 0;
3173 // in the following three cases, the instance created from the component
3174 // has a property which is a copy of the scarce resource; hence, the
3175 // resource should NOT be detached prior to deletion of the object instance,
3176 // unless the resource is destroyed explicitly.
3177 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3178 object = component.create();
3179 QVERIFY(object != 0);
3180 QVERIFY(object->property("scarceResourceCopy").isValid());
3181 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3182 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3183 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3184 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3187 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3188 object = componentTwo.create();
3189 QVERIFY(object != 0);
3190 QVERIFY(object->property("scarceResourceCopy").isValid());
3191 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3192 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3193 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3194 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3197 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3198 object = componentThree.create();
3199 QVERIFY(object != 0);
3200 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3201 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3202 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3203 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3206 // in the following three cases, no other copy should exist in memory,
3207 // and so it should be detached (unless explicitly preserved).
3208 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3209 object = componentFour.create();
3210 QVERIFY(object != 0);
3211 QVERIFY(object->property("scarceResourceTest").isValid());
3212 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3213 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3214 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3215 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3218 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3219 object = componentFive.create();
3220 QVERIFY(object != 0);
3221 QVERIFY(object->property("scarceResourceTest").isValid());
3222 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3223 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3224 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3225 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3228 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3229 object = componentSix.create();
3230 QVERIFY(object != 0);
3231 QVERIFY(object->property("scarceResourceTest").isValid());
3232 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3233 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3234 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3235 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3238 // test that scarce resources are handled correctly for imports
3239 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3240 object = componentSeven.create();
3241 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3242 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3245 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3246 object = componentEight.create();
3247 QVERIFY(object != 0);
3248 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3249 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3252 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3253 object = componentNine.create();
3254 QVERIFY(object != 0);
3255 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3256 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3257 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3258 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3259 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3260 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3263 // test that scarce resources are handled properly in signal invocation
3264 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3265 object = componentTen.create();
3266 QVERIFY(object != 0);
3267 QObject *srsc = object->findChild<QObject*>("srsc");
3269 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3270 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3271 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3272 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3273 QMetaObject::invokeMethod(srsc, "testSignal");
3274 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3275 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3276 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3277 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3278 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3279 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3280 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3281 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3282 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3283 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3286 // test that scarce resources are handled properly from js functions in qml files
3287 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3288 object = componentEleven.create();
3289 QVERIFY(object != 0);
3290 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3291 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3292 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3293 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3294 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3295 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3296 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3297 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3298 QMetaObject::invokeMethod(object, "releaseScarceResource");
3299 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3300 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3301 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3302 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3305 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3306 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3307 object = componentTwelve.create();
3308 QVERIFY(object != 0);
3309 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3310 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3311 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3312 QString srp_name = object->property("srp_name").toString();
3313 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3314 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3315 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3316 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3317 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3318 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3319 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3323 void tst_qdeclarativeecmascript::propertyChangeSlots()
3325 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3326 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3327 QObject *object = component.create();
3328 QVERIFY(object != 0);
3331 // ensure that invalid property names fail properly.
3332 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3333 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3334 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3335 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3336 object = e1.create();
3337 QVERIFY(object == 0);
3340 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3341 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3342 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3343 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3344 object = e2.create();
3345 QVERIFY(object == 0);
3348 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3349 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3350 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3351 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3352 object = e3.create();
3353 QVERIFY(object == 0);
3356 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3357 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3358 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3359 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3360 object = e4.create();
3361 QVERIFY(object == 0);
3365 void tst_qdeclarativeecmascript::propertyVar_data()
3367 QTest::addColumn<QUrl>("qmlFile");
3370 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3371 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3372 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3373 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3374 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3375 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3376 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3377 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3378 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3381 void tst_qdeclarativeecmascript::propertyVar()
3383 QFETCH(QUrl, qmlFile);
3385 QDeclarativeComponent component(&engine, qmlFile);
3386 QObject *object = component.create();
3387 QVERIFY(object != 0);
3389 QCOMPARE(object->property("test").toBool(), true);
3394 // Tests that we can write QVariant values to var properties from C++
3395 void tst_qdeclarativeecmascript::propertyVarCpp()
3397 QObject *object = 0;
3399 // ensure that writing to and reading from a var property from cpp works as required.
3400 // Literal values stored in var properties can be read and written as QVariants
3401 // of a specific type, whereas object values are read as QVariantMaps.
3402 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3403 object = component.create();
3404 QVERIFY(object != 0);
3405 // assign int to property var that currently has int assigned
3406 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3407 QCOMPARE(object->property("varBound"), QVariant(15));
3408 QCOMPARE(object->property("intBound"), QVariant(15));
3409 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3410 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3411 // assign string to property var that current has bool assigned
3412 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3413 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3414 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3415 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3416 // now enforce behaviour when accessing JavaScript objects from cpp.
3417 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3421 static void gc(QDeclarativeEngine &engine)
3423 engine.collectGarbage();
3424 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3427 void tst_qdeclarativeecmascript::propertyVarOwnership()
3429 // Referenced JS objects are not collected
3431 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3432 QObject *object = component.create();
3433 QVERIFY(object != 0);
3434 QCOMPARE(object->property("test").toBool(), false);
3435 QMetaObject::invokeMethod(object, "runTest");
3436 QCOMPARE(object->property("test").toBool(), true);
3439 // Referenced JS objects are not collected
3441 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3442 QObject *object = component.create();
3443 QVERIFY(object != 0);
3444 QCOMPARE(object->property("test").toBool(), false);
3445 QMetaObject::invokeMethod(object, "runTest");
3446 QCOMPARE(object->property("test").toBool(), true);
3449 // Qt objects are not collected until they've been dereferenced
3451 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3452 QObject *object = component.create();
3453 QVERIFY(object != 0);
3455 QCOMPARE(object->property("test2").toBool(), false);
3456 QCOMPARE(object->property("test2").toBool(), false);
3458 QMetaObject::invokeMethod(object, "runTest");
3459 QCOMPARE(object->property("test1").toBool(), true);
3461 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3462 QVERIFY(!referencedObject.isNull());
3464 QVERIFY(!referencedObject.isNull());
3466 QMetaObject::invokeMethod(object, "runTest2");
3467 QCOMPARE(object->property("test2").toBool(), true);
3469 QVERIFY(referencedObject.isNull());
3473 // Self reference does not prevent Qt object collection
3475 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3476 QObject *object = component.create();
3477 QVERIFY(object != 0);
3479 QCOMPARE(object->property("test").toBool(), true);
3481 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3482 QVERIFY(!referencedObject.isNull());
3484 QVERIFY(!referencedObject.isNull());
3486 QMetaObject::invokeMethod(object, "runTest");
3488 QVERIFY(referencedObject.isNull());
3494 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3496 // The childObject has a reference to a different QObject. We want to ensure
3497 // that the different item will not be cleaned up until required. IE, the childObject
3498 // has implicit ownership of the constructed QObject.
3499 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3500 QObject *object = component.create();
3501 QVERIFY(object != 0);
3502 QMetaObject::invokeMethod(object, "assignCircular");
3503 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3504 QObject *rootObject = object->property("vp").value<QObject*>();
3505 QVERIFY(rootObject != 0);
3506 QObject *childObject = rootObject->findChild<QObject*>("text");
3507 QVERIFY(childObject != 0);
3508 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3509 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3510 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3511 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3512 QVERIFY(!qobjectGuard.isNull());
3513 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3514 QVERIFY(!qobjectGuard.isNull());
3515 QMetaObject::invokeMethod(object, "deassignCircular");
3516 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3517 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3521 void tst_qdeclarativeecmascript::propertyVarReparent()
3523 // ensure that nothing breaks if we re-parent objects
3524 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3525 QObject *object = component.create();
3526 QVERIFY(object != 0);
3527 QMetaObject::invokeMethod(object, "assignVarProp");
3528 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3529 QObject *rect = object->property("vp").value<QObject*>();
3530 QObject *text = rect->findChild<QObject*>("textOne");
3531 QObject *text2 = rect->findChild<QObject*>("textTwo");
3532 QWeakPointer<QObject> rectGuard(rect);
3533 QWeakPointer<QObject> textGuard(text);
3534 QWeakPointer<QObject> text2Guard(text2);
3535 QVERIFY(!rectGuard.isNull());
3536 QVERIFY(!textGuard.isNull());
3537 QVERIFY(!text2Guard.isNull());
3538 QCOMPARE(text->property("textCanary").toInt(), 11);
3539 QCOMPARE(text2->property("textCanary").toInt(), 12);
3540 // now construct an image which we will reparent.
3541 QMetaObject::invokeMethod(text2, "constructQObject");
3542 QObject *image = text2->property("vp").value<QObject*>();
3543 QWeakPointer<QObject> imageGuard(image);
3544 QVERIFY(!imageGuard.isNull());
3545 QCOMPARE(image->property("imageCanary").toInt(), 13);
3546 // now reparent the "Image" object (currently, it has JS ownership)
3547 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3548 QMetaObject::invokeMethod(text2, "deassignVp");
3549 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3550 QCOMPARE(text->property("textCanary").toInt(), 11);
3551 QCOMPARE(text2->property("textCanary").toInt(), 22);
3552 QVERIFY(!imageGuard.isNull()); // should still be alive.
3553 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3554 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3555 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3556 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3560 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3562 // sometimes reparenting can cause problems
3563 // (eg, if the ctxt is collected, varproperties are no longer available)
3564 // this test ensures that no crash occurs in that situation.
3565 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3566 QObject *object = component.create();
3567 QVERIFY(object != 0);
3568 QMetaObject::invokeMethod(object, "assignVarProp");
3569 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3570 QObject *rect = object->property("vp").value<QObject*>();
3571 QObject *text = rect->findChild<QObject*>("textOne");
3572 QObject *text2 = rect->findChild<QObject*>("textTwo");
3573 QWeakPointer<QObject> rectGuard(rect);
3574 QWeakPointer<QObject> textGuard(text);
3575 QWeakPointer<QObject> text2Guard(text2);
3576 QVERIFY(!rectGuard.isNull());
3577 QVERIFY(!textGuard.isNull());
3578 QVERIFY(!text2Guard.isNull());
3579 QCOMPARE(text->property("textCanary").toInt(), 11);
3580 QCOMPARE(text2->property("textCanary").toInt(), 12);
3581 // now construct an image which we will reparent.
3582 QMetaObject::invokeMethod(text2, "constructQObject");
3583 QObject *image = text2->property("vp").value<QObject*>();
3584 QWeakPointer<QObject> imageGuard(image);
3585 QVERIFY(!imageGuard.isNull());
3586 QCOMPARE(image->property("imageCanary").toInt(), 13);
3587 // now reparent the "Image" object (currently, it has JS ownership)
3588 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3589 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3590 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3591 QVERIFY(!imageGuard.isNull()); // should still be alive.
3592 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3594 QVERIFY(imageGuard.isNull()); // should now be dead.
3597 void tst_qdeclarativeecmascript::propertyVarCircular()
3599 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3600 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3601 QObject *object = component.create();
3602 QVERIFY(object != 0);
3603 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3604 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3605 QCOMPARE(object->property("canaryInt"), QVariant(5));
3606 QVariant canaryResourceVariant = object->property("canaryResource");
3607 QVERIFY(canaryResourceVariant.isValid());
3608 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3609 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3610 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3611 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3612 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3613 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3614 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3615 QCOMPARE(object->property("canaryInt"), QVariant(2));
3616 QCOMPARE(object->property("canaryResource"), QVariant(1));
3617 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3621 void tst_qdeclarativeecmascript::propertyVarCircular2()
3623 // track deletion of JS-owned parent item with Cpp-owned child
3624 // where the child has a var property referencing its parent.
3625 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3626 QObject *object = component.create();
3627 QVERIFY(object != 0);
3628 QMetaObject::invokeMethod(object, "assignCircular");
3629 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3630 QObject *rootObject = object->property("vp").value<QObject*>();
3631 QVERIFY(rootObject != 0);
3632 QObject *childObject = rootObject->findChild<QObject*>("text");
3633 QVERIFY(childObject != 0);
3634 QWeakPointer<QObject> rootObjectTracker(rootObject);
3635 QVERIFY(!rootObjectTracker.isNull());
3636 QWeakPointer<QObject> childObjectTracker(childObject);
3637 QVERIFY(!childObjectTracker.isNull());
3639 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3640 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3641 QMetaObject::invokeMethod(object, "deassignCircular");
3642 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3643 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3644 QVERIFY(childObjectTracker.isNull()); // should have been collected
3648 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3650 *(int*)(parameter) += 1;
3651 qPersistentDispose(object);
3654 void tst_qdeclarativeecmascript::propertyVarInheritance()
3656 int propertyVarWeakRefCallbackCount = 0;
3658 // enforce behaviour regarding element inheritance - ensure handle disposal.
3659 // The particular component under test here has a chain of references.
3660 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3661 QObject *object = component.create();
3662 QVERIFY(object != 0);
3663 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3664 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3665 // we want to be able to track when the varProperties array of the last metaobject is disposed
3666 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3667 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*>();
3668 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3669 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3670 v8::Persistent<v8::Value> icoCanaryHandle;
3671 v8::Persistent<v8::Value> ccoCanaryHandle;
3674 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3675 // public function which can return us a handle to something in the varProperties array.
3676 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3677 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3678 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3679 // as the varproperties array of each vmemo still references the resource.
3680 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3681 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3683 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3685 // now we deassign the var prop, which should trigger collection of item subtrees.
3686 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3687 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3688 // ensure that there are only weak handles to the underlying varProperties array remaining.
3690 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3692 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3693 // to what remains are weak, all varProperties arrays must have been collected.
3696 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3698 int propertyVarWeakRefCallbackCount = 0;
3700 // The particular component under test here does NOT have a chain of references; the
3701 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3702 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3703 QObject *object = component.create();
3704 QVERIFY(object != 0);
3705 QMetaObject::invokeMethod(object, "assignCircular");
3706 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3707 QObject *rootObject = object->property("vp").value<QObject*>();
3708 QVERIFY(rootObject != 0);
3709 QObject *childObject = rootObject->findChild<QObject*>("text");
3710 QVERIFY(childObject != 0);
3711 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3712 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3713 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3716 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3717 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3718 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3720 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3721 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3723 QMetaObject::invokeMethod(object, "deassignCircular");
3724 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3725 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3729 // Ensure that QObject type conversion works on binding assignment
3730 void tst_qdeclarativeecmascript::elementAssign()
3732 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3734 QObject *object = component.create();
3735 QVERIFY(object != 0);
3737 QCOMPARE(object->property("test").toBool(), true);
3743 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3745 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3747 QObject *object = component.create();
3748 QVERIFY(object != 0);
3750 QCOMPARE(object->property("test").toBool(), true);
3756 void tst_qdeclarativeecmascript::objectConversion()
3758 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3760 QObject *object = component.create();
3761 QVERIFY(object != 0);
3763 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3764 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3771 void tst_qdeclarativeecmascript::booleanConversion()
3773 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3775 QObject *object = component.create();
3776 QVERIFY(object != 0);
3778 QCOMPARE(object->property("test_true1").toBool(), true);
3779 QCOMPARE(object->property("test_true2").toBool(), true);
3780 QCOMPARE(object->property("test_true3").toBool(), true);
3781 QCOMPARE(object->property("test_true4").toBool(), true);
3782 QCOMPARE(object->property("test_true5").toBool(), true);
3784 QCOMPARE(object->property("test_false1").toBool(), false);
3785 QCOMPARE(object->property("test_false2").toBool(), false);
3786 QCOMPARE(object->property("test_false3").toBool(), false);
3791 void tst_qdeclarativeecmascript::handleReferenceManagement()
3796 // Linear QObject reference
3797 QDeclarativeEngine hrmEngine;
3798 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3799 QObject *object = component.create();
3800 QVERIFY(object != 0);
3801 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3802 cro->setDtorCount(&dtorCount);
3803 QMetaObject::invokeMethod(object, "createReference");
3805 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3807 hrmEngine.collectGarbage();
3808 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3809 QCOMPARE(dtorCount, 3);
3814 // Circular QObject reference
3815 QDeclarativeEngine hrmEngine;
3816 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3817 QObject *object = component.create();
3818 QVERIFY(object != 0);
3819 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3820 cro->setDtorCount(&dtorCount);
3821 QMetaObject::invokeMethod(object, "circularReference");
3823 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3825 hrmEngine.collectGarbage();
3826 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3827 QCOMPARE(dtorCount, 3);
3832 // Linear handle reference
3833 QDeclarativeEngine hrmEngine;
3834 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3835 QObject *object = component.create();
3836 QVERIFY(object != 0);
3837 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3839 crh->setDtorCount(&dtorCount);
3840 QMetaObject::invokeMethod(object, "createReference");
3841 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3842 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3843 QVERIFY(first != 0);
3844 QVERIFY(second != 0);
3845 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3846 // now we have to reparent second and make second owned by JS.
3847 second->setParent(0);
3848 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3850 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3852 hrmEngine.collectGarbage();
3853 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3854 QCOMPARE(dtorCount, 3);
3859 // Circular handle reference
3860 QDeclarativeEngine hrmEngine;
3861 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3862 QObject *object = component.create();
3863 QVERIFY(object != 0);
3864 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3866 crh->setDtorCount(&dtorCount);
3867 QMetaObject::invokeMethod(object, "circularReference");
3868 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3869 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3870 QVERIFY(first != 0);
3871 QVERIFY(second != 0);
3872 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3873 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3874 // now we have to reparent and change ownership.
3875 first->setParent(0);
3876 second->setParent(0);
3877 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3878 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3880 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3882 hrmEngine.collectGarbage();
3883 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3884 QCOMPARE(dtorCount, 3);
3889 // multiple engine interaction - linear reference
3890 QDeclarativeEngine hrmEngine1;
3891 QDeclarativeEngine hrmEngine2;
3892 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3893 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3894 QObject *object1 = component1.create();
3895 QObject *object2 = component2.create();
3896 QVERIFY(object1 != 0);
3897 QVERIFY(object2 != 0);
3898 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3899 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3902 crh1->setDtorCount(&dtorCount);
3903 crh2->setDtorCount(&dtorCount);
3904 QMetaObject::invokeMethod(object1, "createReference");
3905 QMetaObject::invokeMethod(object2, "createReference");
3906 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3907 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3908 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3909 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3910 QVERIFY(first1 != 0);
3911 QVERIFY(second1 != 0);
3912 QVERIFY(first2 != 0);
3913 QVERIFY(second2 != 0);
3914 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3915 // now we have to reparent second2 and make second2 owned by JS.
3916 second2->setParent(0);
3917 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3919 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3920 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3923 hrmEngine1.collectGarbage();
3924 hrmEngine2.collectGarbage();
3925 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3926 QCOMPARE(dtorCount, 6);
3931 // multiple engine interaction - circular reference
3932 QDeclarativeEngine hrmEngine1;
3933 QDeclarativeEngine hrmEngine2;
3934 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3935 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3936 QObject *object1 = component1.create();
3937 QObject *object2 = component2.create();
3938 QVERIFY(object1 != 0);
3939 QVERIFY(object2 != 0);
3940 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3941 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3944 crh1->setDtorCount(&dtorCount);
3945 crh2->setDtorCount(&dtorCount);
3946 QMetaObject::invokeMethod(object1, "createReference");
3947 QMetaObject::invokeMethod(object2, "createReference");
3948 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3949 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3950 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3951 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3952 QVERIFY(first1 != 0);
3953 QVERIFY(second1 != 0);
3954 QVERIFY(first2 != 0);
3955 QVERIFY(second2 != 0);
3956 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3957 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3958 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3959 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3960 // now we have to reparent and change ownership to JS.
3961 first1->setParent(0);
3962 second1->setParent(0);
3963 first2->setParent(0);
3964 second2->setParent(0);
3965 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3966 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3967 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3968 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3970 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3971 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3974 hrmEngine1.collectGarbage();
3975 hrmEngine2.collectGarbage();
3976 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3977 QCOMPARE(dtorCount, 6);
3982 // multiple engine interaction - linear reference with engine deletion
3983 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3984 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3985 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3986 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3987 QObject *object1 = component1.create();
3988 QObject *object2 = component2.create();
3989 QVERIFY(object1 != 0);
3990 QVERIFY(object2 != 0);
3991 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3992 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3995 crh1->setDtorCount(&dtorCount);
3996 crh2->setDtorCount(&dtorCount);
3997 QMetaObject::invokeMethod(object1, "createReference");
3998 QMetaObject::invokeMethod(object2, "createReference");
3999 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4000 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4001 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4002 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4003 QVERIFY(first1 != 0);
4004 QVERIFY(second1 != 0);
4005 QVERIFY(first2 != 0);
4006 QVERIFY(second2 != 0);
4007 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4008 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4009 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4010 // now we have to reparent and change ownership to JS.
4011 first1->setParent(crh1);
4012 second1->setParent(0);
4013 first2->setParent(0);
4014 second2->setParent(0);
4015 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4016 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4017 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4019 QCOMPARE(dtorCount, 0);
4022 QCOMPARE(dtorCount, 0);
4025 hrmEngine1->collectGarbage();
4026 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4027 QCOMPARE(dtorCount, 6);
4032 void tst_qdeclarativeecmascript::stringArg()
4034 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4035 QObject *object = component.create();
4036 QVERIFY(object != 0);
4037 QMetaObject::invokeMethod(object, "success");
4038 QVERIFY(object->property("returnValue").toBool());
4040 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4041 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4042 QMetaObject::invokeMethod(object, "failure");
4043 QVERIFY(object->property("returnValue").toBool());
4048 void tst_qdeclarativeecmascript::readonlyDeclaration()
4050 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4052 QObject *object = component.create();
4053 QVERIFY(object != 0);
4055 QCOMPARE(object->property("test").toBool(), true);
4060 Q_DECLARE_METATYPE(QList<int>)
4061 Q_DECLARE_METATYPE(QList<qreal>)
4062 Q_DECLARE_METATYPE(QList<bool>)
4063 Q_DECLARE_METATYPE(QList<QString>)
4064 Q_DECLARE_METATYPE(QList<QUrl>)
4065 void tst_qdeclarativeecmascript::sequenceConversionRead()
4068 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4069 QDeclarativeComponent component(&engine, qmlFile);
4070 QObject *object = component.create();
4071 QVERIFY(object != 0);
4072 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4075 QMetaObject::invokeMethod(object, "readSequences");
4076 QList<int> intList; intList << 1 << 2 << 3 << 4;
4077 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4078 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4079 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4080 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4081 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4082 QList<bool> boolList; boolList << true << false << true << false;
4083 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4084 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4085 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4086 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4087 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4088 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4089 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4090 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4091 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4092 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4093 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4095 QMetaObject::invokeMethod(object, "readSequenceElements");
4096 QCOMPARE(object->property("intVal").toInt(), 2);
4097 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4098 QCOMPARE(object->property("boolVal").toBool(), false);
4099 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4100 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4101 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4103 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4104 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4106 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4107 QDeclarativeProperty seqProp(seq, "intListProperty");
4108 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4109 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4110 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4112 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4113 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4119 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4120 QDeclarativeComponent component(&engine, qmlFile);
4121 QObject *object = component.create();
4122 QVERIFY(object != 0);
4123 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4126 // we haven't registered QList<QPoint> as a sequence type.
4127 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4128 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4129 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4130 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4132 QMetaObject::invokeMethod(object, "performTest");
4134 // QList<QPoint> has not been registered as a sequence type.
4135 QCOMPARE(object->property("pointListLength").toInt(), 0);
4136 QVERIFY(!object->property("pointList").isValid());
4137 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4138 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4139 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4145 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4148 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4149 QDeclarativeComponent component(&engine, qmlFile);
4150 QObject *object = component.create();
4151 QVERIFY(object != 0);
4152 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4155 QMetaObject::invokeMethod(object, "writeSequences");
4156 QCOMPARE(object->property("success").toBool(), true);
4158 QMetaObject::invokeMethod(object, "writeSequenceElements");
4159 QCOMPARE(object->property("success").toBool(), true);
4161 QMetaObject::invokeMethod(object, "writeOtherElements");
4162 QCOMPARE(object->property("success").toBool(), true);
4164 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4165 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4171 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4172 QDeclarativeComponent component(&engine, qmlFile);
4173 QObject *object = component.create();
4174 QVERIFY(object != 0);
4175 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4178 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4179 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4180 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4182 QMetaObject::invokeMethod(object, "performTest");
4184 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4185 QCOMPARE(seq->pointListProperty(), pointList);
4191 void tst_qdeclarativeecmascript::sequenceConversionArray()
4193 // ensure that in JS the returned sequences act just like normal JS Arrays.
4194 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4195 QDeclarativeComponent component(&engine, qmlFile);
4196 QObject *object = component.create();
4197 QVERIFY(object != 0);
4198 //QMetaObject::invokeMethod(object, "indexedAccess");
4199 //QVERIFY(object->property("success").toBool());
4200 //QMetaObject::invokeMethod(object, "arrayOperations");
4201 //QVERIFY(object->property("success").toBool());
4202 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4203 QVERIFY(object->property("success").toBool());
4204 //QMetaObject::invokeMethod(object, "testReferenceDeletion");
4205 //QCOMPARE(object->property("referenceDeletion").toBool(), true);
4209 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4211 // ensure that sequence conversion operations work correctly in a worker thread
4212 // and that serialisation between the main and worker thread succeeds.
4213 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4214 QDeclarativeComponent component(&engine, qmlFile);
4215 QObject *object = component.create();
4216 QVERIFY(object != 0);
4218 QMetaObject::invokeMethod(object, "testIntSequence");
4219 QTRY_VERIFY(object->property("finished").toBool());
4220 QVERIFY(object->property("success").toBool());
4222 QMetaObject::invokeMethod(object, "testQrealSequence");
4223 QTRY_VERIFY(object->property("finished").toBool());
4224 QVERIFY(object->property("success").toBool());
4226 QMetaObject::invokeMethod(object, "testBoolSequence");
4227 QTRY_VERIFY(object->property("finished").toBool());
4228 QVERIFY(object->property("success").toBool());
4230 QMetaObject::invokeMethod(object, "testStringSequence");
4231 QTRY_VERIFY(object->property("finished").toBool());
4232 QVERIFY(object->property("success").toBool());
4234 QMetaObject::invokeMethod(object, "testQStringSequence");
4235 QTRY_VERIFY(object->property("finished").toBool());
4236 QVERIFY(object->property("success").toBool());
4238 QMetaObject::invokeMethod(object, "testUrlSequence");
4239 QTRY_VERIFY(object->property("finished").toBool());
4240 QVERIFY(object->property("success").toBool());
4245 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4248 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4249 QDeclarativeComponent component(&engine, qmlFile);
4250 QObject *object = component.create();
4251 QVERIFY(object != 0);
4252 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4253 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4254 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4255 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4256 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4261 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4262 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4263 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4264 QDeclarativeComponent component(&engine, qmlFile);
4265 QObject *object = component.create();
4266 QVERIFY(object != 0);
4271 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4273 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4274 QDeclarativeComponent component(&engine, qmlFile);
4275 QObject *object = component.create();
4276 QVERIFY(object != 0);
4277 QMetaObject::invokeMethod(object, "testCopySequences");
4278 QCOMPARE(object->property("success").toBool(), true);
4279 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4280 QCOMPARE(object->property("success").toBool(), true);
4281 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4282 QCOMPARE(object->property("success").toBool(), true);
4286 // Test that assigning a null object works
4287 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4288 void tst_qdeclarativeecmascript::nullObjectBinding()
4290 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4292 QObject *object = component.create();
4293 QVERIFY(object != 0);
4295 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4300 // Test that bindings don't evaluate once the engine has been destroyed
4301 void tst_qdeclarativeecmascript::deletedEngine()
4303 QDeclarativeEngine *engine = new QDeclarativeEngine;
4304 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4306 QObject *object = component.create();
4307 QVERIFY(object != 0);
4309 QCOMPARE(object->property("a").toInt(), 39);
4310 object->setProperty("b", QVariant(9));
4311 QCOMPARE(object->property("a").toInt(), 117);
4315 QCOMPARE(object->property("a").toInt(), 117);
4316 object->setProperty("b", QVariant(10));
4317 QCOMPARE(object->property("a").toInt(), 117);
4322 // Test the crashing part of QTBUG-9705
4323 void tst_qdeclarativeecmascript::libraryScriptAssert()
4325 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4327 QObject *object = component.create();
4328 QVERIFY(object != 0);
4333 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4335 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4337 QObject *object = component.create();
4338 QVERIFY(object != 0);
4340 QCOMPARE(object->property("test1").toInt(), 10);
4341 QCOMPARE(object->property("test2").toInt(), 11);
4343 object->setProperty("runTest", true);
4345 QCOMPARE(object->property("test1"), QVariant());
4346 QCOMPARE(object->property("test2"), QVariant());
4352 void tst_qdeclarativeecmascript::qtbug_9792()
4354 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4356 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4358 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4359 QVERIFY(object != 0);
4361 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4362 object->basicSignal();
4366 transientErrorsMsgCount = 0;
4367 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4369 object->basicSignal();
4371 qInstallMsgHandler(old);
4373 QCOMPARE(transientErrorsMsgCount, 0);
4378 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4379 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4381 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4383 QObject *o = component.create();
4386 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4387 QVERIFY(nested != 0);
4389 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4392 nested = qvariant_cast<QObject *>(o->property("object"));
4393 QVERIFY(nested == 0);
4395 // If the bug is present, the next line will crash
4399 // Test that we shut down without stupid warnings
4400 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4403 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4405 QObject *o = component.create();
4407 transientErrorsMsgCount = 0;
4408 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4412 qInstallMsgHandler(old);
4414 QCOMPARE(transientErrorsMsgCount, 0);
4419 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4421 QObject *o = component.create();
4423 transientErrorsMsgCount = 0;
4424 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4428 qInstallMsgHandler(old);
4430 QCOMPARE(transientErrorsMsgCount, 0);
4434 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4437 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4439 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4442 QVERIFY(o->objectProperty() != 0);
4444 o->setProperty("runTest", true);
4446 QVERIFY(o->objectProperty() == 0);
4452 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4454 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4457 QVERIFY(o->objectProperty() == 0);
4463 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4465 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4467 QString url = component.url().toString();
4468 QString warning = url + ":4: Unable to assign a function to a property.";
4469 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4471 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4474 QVERIFY(!o->property("a").isValid());
4479 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4481 QFETCH(QString, triggerProperty);
4483 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4484 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4486 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4488 QVERIFY(!o->property("a").isValid());
4490 o->setProperty("aNumber", QVariant(5));
4491 o->setProperty(triggerProperty.toUtf8().constData(), true);
4492 QCOMPARE(o->property("a"), QVariant(50));
4494 o->setProperty("aNumber", QVariant(10));
4495 QCOMPARE(o->property("a"), QVariant(100));
4500 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4502 QTest::addColumn<QString>("triggerProperty");
4504 QTest::newRow("assign to property") << "assignToProperty";
4505 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4507 QTest::newRow("assign to value type") << "assignToValueType";
4509 QTest::newRow("use 'this'") << "assignWithThis";
4510 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4513 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4515 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4516 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4518 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4520 QVERIFY(!o->property("a").isValid());
4522 o->setProperty("assignFuncWithoutReturn", true);
4523 QVERIFY(!o->property("a").isValid());
4525 QString url = component.url().toString();
4526 QString warning = url + ":67: Unable to assign QString to int";
4527 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4528 o->setProperty("assignWrongType", true);
4530 warning = url + ":71: Unable to assign QString to int";
4531 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4532 o->setProperty("assignWrongTypeToValueType", true);
4537 void tst_qdeclarativeecmascript::eval()
4539 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4541 QObject *o = component.create();
4544 QCOMPARE(o->property("test1").toBool(), true);
4545 QCOMPARE(o->property("test2").toBool(), true);
4546 QCOMPARE(o->property("test3").toBool(), true);
4547 QCOMPARE(o->property("test4").toBool(), true);
4548 QCOMPARE(o->property("test5").toBool(), true);
4553 void tst_qdeclarativeecmascript::function()
4555 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4557 QObject *o = component.create();
4560 QCOMPARE(o->property("test1").toBool(), true);
4561 QCOMPARE(o->property("test2").toBool(), true);
4562 QCOMPARE(o->property("test3").toBool(), true);
4567 // Test the "Qt.include" method
4568 void tst_qdeclarativeecmascript::include()
4570 // Non-library relative include
4572 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4573 QObject *o = component.create();
4576 QCOMPARE(o->property("test0").toInt(), 99);
4577 QCOMPARE(o->property("test1").toBool(), true);
4578 QCOMPARE(o->property("test2").toBool(), true);
4579 QCOMPARE(o->property("test2_1").toBool(), true);
4580 QCOMPARE(o->property("test3").toBool(), true);
4581 QCOMPARE(o->property("test3_1").toBool(), true);
4586 // Library relative include
4588 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4589 QObject *o = component.create();
4592 QCOMPARE(o->property("test0").toInt(), 99);
4593 QCOMPARE(o->property("test1").toBool(), true);
4594 QCOMPARE(o->property("test2").toBool(), true);
4595 QCOMPARE(o->property("test2_1").toBool(), true);
4596 QCOMPARE(o->property("test3").toBool(), true);
4597 QCOMPARE(o->property("test3_1").toBool(), true);
4604 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4605 QObject *o = component.create();
4608 QCOMPARE(o->property("test1").toBool(), true);
4609 QCOMPARE(o->property("test2").toBool(), true);
4610 QCOMPARE(o->property("test3").toBool(), true);
4611 QCOMPARE(o->property("test4").toBool(), true);
4612 QCOMPARE(o->property("test5").toBool(), true);
4613 QCOMPARE(o->property("test6").toBool(), true);
4618 // Including file with ".pragma library"
4620 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4621 QObject *o = component.create();
4623 QCOMPARE(o->property("test1").toInt(), 100);
4630 TestHTTPServer server(8111);
4631 QVERIFY(server.isValid());
4632 server.serveDirectory(TESTDATA(""));
4634 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4635 QObject *o = component.create();
4638 QTRY_VERIFY(o->property("done").toBool() == true);
4639 QTRY_VERIFY(o->property("done2").toBool() == true);
4641 QCOMPARE(o->property("test1").toBool(), true);
4642 QCOMPARE(o->property("test2").toBool(), true);
4643 QCOMPARE(o->property("test3").toBool(), true);
4644 QCOMPARE(o->property("test4").toBool(), true);
4645 QCOMPARE(o->property("test5").toBool(), true);
4647 QCOMPARE(o->property("test6").toBool(), true);
4648 QCOMPARE(o->property("test7").toBool(), true);
4649 QCOMPARE(o->property("test8").toBool(), true);
4650 QCOMPARE(o->property("test9").toBool(), true);
4651 QCOMPARE(o->property("test10").toBool(), true);
4658 TestHTTPServer server(8111);
4659 QVERIFY(server.isValid());
4660 server.serveDirectory(TESTDATA(""));
4662 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4663 QObject *o = component.create();
4666 QTRY_VERIFY(o->property("done").toBool() == true);
4668 QCOMPARE(o->property("test1").toBool(), true);
4669 QCOMPARE(o->property("test2").toBool(), true);
4670 QCOMPARE(o->property("test3").toBool(), true);
4676 void tst_qdeclarativeecmascript::signalHandlers()
4678 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4679 QObject *o = component.create();
4682 QVERIFY(o->property("count").toInt() == 0);
4683 QMetaObject::invokeMethod(o, "testSignalCall");
4684 QCOMPARE(o->property("count").toInt(), 1);
4686 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4687 QCOMPARE(o->property("count").toInt(), 1);
4688 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4690 QVERIFY(o->property("funcCount").toInt() == 0);
4691 QMetaObject::invokeMethod(o, "testSignalConnection");
4692 QCOMPARE(o->property("funcCount").toInt(), 1);
4694 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4695 QCOMPARE(o->property("funcCount").toInt(), 2);
4697 QMetaObject::invokeMethod(o, "testSignalDefined");
4698 QCOMPARE(o->property("definedResult").toBool(), true);
4700 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4701 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4706 void tst_qdeclarativeecmascript::qtbug_10696()
4708 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4709 QObject *o = component.create();
4714 void tst_qdeclarativeecmascript::qtbug_11606()
4716 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4717 QObject *o = component.create();
4719 QCOMPARE(o->property("test").toBool(), true);
4723 void tst_qdeclarativeecmascript::qtbug_11600()
4725 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4726 QObject *o = component.create();
4728 QCOMPARE(o->property("test").toBool(), true);
4732 // Reading and writing non-scriptable properties should fail
4733 void tst_qdeclarativeecmascript::nonscriptable()
4735 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4736 QObject *o = component.create();
4738 QCOMPARE(o->property("readOk").toBool(), true);
4739 QCOMPARE(o->property("writeOk").toBool(), true);
4743 // deleteLater() should not be callable from QML
4744 void tst_qdeclarativeecmascript::deleteLater()
4746 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4747 QObject *o = component.create();
4749 QCOMPARE(o->property("test").toBool(), true);
4753 void tst_qdeclarativeecmascript::in()
4755 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4756 QObject *o = component.create();
4758 QCOMPARE(o->property("test1").toBool(), true);
4759 QCOMPARE(o->property("test2").toBool(), true);
4763 void tst_qdeclarativeecmascript::typeOf()
4765 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4766 QObject *o = component.create();
4768 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4769 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4770 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4771 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4772 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4773 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4774 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4775 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4776 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4777 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4782 void tst_qdeclarativeecmascript::sharedAttachedObject()
4784 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4785 QObject *o = component.create();
4787 QCOMPARE(o->property("test1").toBool(), true);
4788 QCOMPARE(o->property("test2").toBool(), true);
4793 void tst_qdeclarativeecmascript::objectName()
4795 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4796 QObject *o = component.create();
4799 QCOMPARE(o->property("test1").toString(), QString("hello"));
4800 QCOMPARE(o->property("test2").toString(), QString("ell"));
4802 o->setObjectName("world");
4804 QCOMPARE(o->property("test1").toString(), QString("world"));
4805 QCOMPARE(o->property("test2").toString(), QString("orl"));
4810 void tst_qdeclarativeecmascript::writeRemovesBinding()
4812 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4813 QObject *o = component.create();
4816 QCOMPARE(o->property("test").toBool(), true);
4821 // Test bindings assigned to alias properties actually assign to the alias' target
4822 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4824 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4825 QObject *o = component.create();
4828 QCOMPARE(o->property("test").toBool(), true);
4833 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4834 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4837 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4838 QObject *o = component.create();
4841 QCOMPARE(o->property("test").toBool(), true);
4847 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4848 QObject *o = component.create();
4851 QCOMPARE(o->property("test").toBool(), true);
4857 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4858 QObject *o = component.create();
4861 QCOMPARE(o->property("test").toBool(), true);
4867 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4868 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4871 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4872 QObject *o = component.create();
4875 QCOMPARE(o->property("test").toBool(), true);
4881 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4882 QObject *o = component.create();
4885 QCOMPARE(o->property("test").toBool(), true);
4891 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4892 QObject *o = component.create();
4895 QCOMPARE(o->property("test").toBool(), true);
4901 // Allow an alais to a composite element
4903 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4905 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4907 QObject *object = component.create();
4908 QVERIFY(object != 0);
4913 void tst_qdeclarativeecmascript::qtbug_20344()
4915 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
4917 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
4918 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
4920 QObject *object = component.create();
4921 QVERIFY(object != 0);
4926 void tst_qdeclarativeecmascript::revisionErrors()
4929 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4930 QString url = component.url().toString();
4932 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4933 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4934 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4936 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4937 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4938 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4939 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4940 QVERIFY(object != 0);
4944 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4945 QString url = component.url().toString();
4947 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4948 // method2, prop2 from MyRevisionedClass not available
4949 // method4, prop4 from MyRevisionedSubclass not available
4950 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4951 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4952 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4953 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4954 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4956 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4957 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4958 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4959 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4960 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4961 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4962 QVERIFY(object != 0);
4966 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4967 QString url = component.url().toString();
4969 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4970 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4971 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4972 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4973 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4974 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4975 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4976 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4977 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4978 QVERIFY(object != 0);
4983 void tst_qdeclarativeecmascript::revision()
4986 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4987 QString url = component.url().toString();
4989 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4990 QVERIFY(object != 0);
4994 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4995 QString url = component.url().toString();
4997 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4998 QVERIFY(object != 0);
5002 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5003 QString url = component.url().toString();
5005 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5006 QVERIFY(object != 0);
5009 // Test that non-root classes can resolve revisioned methods
5011 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5013 QObject *object = component.create();
5014 QVERIFY(object != 0);
5015 QCOMPARE(object->property("test").toReal(), 11.);
5020 void tst_qdeclarativeecmascript::realToInt()
5022 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5023 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5024 QVERIFY(object != 0);
5026 QMetaObject::invokeMethod(object, "test1");
5027 QCOMPARE(object->value(), int(4));
5028 QMetaObject::invokeMethod(object, "test2");
5029 QCOMPARE(object->value(), int(8));
5031 void tst_qdeclarativeecmascript::dynamicString()
5033 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5034 QObject *object = component.create();
5035 QVERIFY(object != 0);
5036 QCOMPARE(object->property("stringProperty").toString(),
5037 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5040 void tst_qdeclarativeecmascript::automaticSemicolon()
5042 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5043 QObject *object = component.create();
5044 QVERIFY(object != 0);
5047 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5048 void tst_qdeclarativeecmascript::doubleEvaluate()
5050 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5051 QObject *object = component.create();
5052 QVERIFY(object != 0);
5053 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5055 QCOMPARE(wc->count(), 1);
5057 wc->setProperty("x", 9);
5059 QCOMPARE(wc->count(), 2);
5064 static QStringList messages;
5065 static void captureMsgHandler(QtMsgType, const char *msg)
5067 messages.append(QLatin1String(msg));
5070 void tst_qdeclarativeecmascript::nonNotifyable()
5072 QV4Compiler::enableV4(false);
5073 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5074 QV4Compiler::enableV4(true);
5076 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5078 QObject *object = component.create();
5079 qInstallMsgHandler(old);
5081 QVERIFY(object != 0);
5083 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5084 component.url().toString() +
5085 QLatin1String(":5 depends on non-NOTIFYable properties:");
5086 QString expected2 = QLatin1String(" ") +
5087 QLatin1String(object->metaObject()->className()) +
5088 QLatin1String("::value");
5090 QCOMPARE(messages.length(), 2);
5091 QCOMPARE(messages.at(0), expected1);
5092 QCOMPARE(messages.at(1), expected2);
5097 void tst_qdeclarativeecmascript::forInLoop()
5099 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5100 QObject *object = component.create();
5101 QVERIFY(object != 0);
5103 QMetaObject::invokeMethod(object, "listProperty");
5105 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5106 QCOMPARE(r.size(), 3);
5107 QCOMPARE(r[0],QLatin1String("0=obj1"));
5108 QCOMPARE(r[1],QLatin1String("1=obj2"));
5109 QCOMPARE(r[2],QLatin1String("2=obj3"));
5111 //TODO: should test for in loop for other objects (such as QObjects) as well.
5116 // An object the binding depends on is deleted while the binding is still running
5117 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5119 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5120 QObject *object = component.create();
5121 QVERIFY(object != 0);
5125 QTEST_MAIN(tst_qdeclarativeecmascript)
5127 #include "tst_qdeclarativeecmascript.moc"