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();
184 void dynamicCreationCrash();
185 void dynamicCreationOwnership();
187 void nullObjectBinding();
188 void deletedEngine();
189 void libraryScriptAssert();
190 void variantsAssignedUndefined();
192 void qtcreatorbug_1289();
193 void noSpuriousWarningsAtShutdown();
194 void canAssignNullToQObject();
195 void functionAssignment_fromBinding();
196 void functionAssignment_fromJS();
197 void functionAssignment_fromJS_data();
198 void functionAssignmentfromJS_invalid();
204 void nonscriptable();
208 void sharedAttachedObject();
210 void writeRemovesBinding();
211 void aliasBindingsAssignCorrectly();
212 void aliasBindingsOverrideTarget();
213 void aliasWritesOverrideBindings();
214 void aliasToCompositeElement();
216 void dynamicString();
218 void signalHandlers();
219 void doubleEvaluate();
221 void nonNotifyable();
222 void deleteWhileBindingRunning();
223 void callQtInvokables();
224 void invokableObjectArg();
225 void invokableObjectRet();
228 void revisionErrors();
231 void automaticSemicolon();
232 void unaryExpression();
235 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
236 QDeclarativeEngine engine;
239 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
241 void tst_qdeclarativeecmascript::assignBasicTypes()
244 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
245 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
246 QVERIFY(object != 0);
247 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
248 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
249 QCOMPARE(object->stringProperty(), QString("Hello World!"));
250 QCOMPARE(object->uintProperty(), uint(10));
251 QCOMPARE(object->intProperty(), -19);
252 QCOMPARE((float)object->realProperty(), float(23.2));
253 QCOMPARE((float)object->doubleProperty(), float(-19.75));
254 QCOMPARE((float)object->floatProperty(), float(8.5));
255 QCOMPARE(object->colorProperty(), QColor("red"));
256 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
257 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
258 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
259 QCOMPARE(object->pointProperty(), QPoint(99,13));
260 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
261 QCOMPARE(object->sizeProperty(), QSize(99, 13));
262 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
263 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
264 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
265 QCOMPARE(object->boolProperty(), true);
266 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
267 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
268 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
272 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
273 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
274 QVERIFY(object != 0);
275 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
276 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
277 QCOMPARE(object->stringProperty(), QString("Hello World!"));
278 QCOMPARE(object->uintProperty(), uint(10));
279 QCOMPARE(object->intProperty(), -19);
280 QCOMPARE((float)object->realProperty(), float(23.2));
281 QCOMPARE((float)object->doubleProperty(), float(-19.75));
282 QCOMPARE((float)object->floatProperty(), float(8.5));
283 QCOMPARE(object->colorProperty(), QColor("red"));
284 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
285 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
286 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
287 QCOMPARE(object->pointProperty(), QPoint(99,13));
288 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
289 QCOMPARE(object->sizeProperty(), QSize(99, 13));
290 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
291 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
292 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
293 QCOMPARE(object->boolProperty(), true);
294 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
295 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
296 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
301 void tst_qdeclarativeecmascript::idShortcutInvalidates()
304 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
305 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
306 QVERIFY(object != 0);
307 QVERIFY(object->objectProperty() != 0);
308 delete object->objectProperty();
309 QVERIFY(object->objectProperty() == 0);
314 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
315 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
316 QVERIFY(object != 0);
317 QVERIFY(object->objectProperty() != 0);
318 delete object->objectProperty();
319 QVERIFY(object->objectProperty() == 0);
324 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
327 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
328 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
329 QVERIFY(object != 0);
330 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
334 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
335 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
336 QVERIFY(object != 0);
337 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
342 void tst_qdeclarativeecmascript::signalAssignment()
345 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
346 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
347 QVERIFY(object != 0);
348 QCOMPARE(object->string(), QString());
349 emit object->basicSignal();
350 QCOMPARE(object->string(), QString("pass"));
355 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
356 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
357 QVERIFY(object != 0);
358 QCOMPARE(object->string(), QString());
359 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
360 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
365 void tst_qdeclarativeecmascript::methods()
368 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
369 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
370 QVERIFY(object != 0);
371 QCOMPARE(object->methodCalled(), false);
372 QCOMPARE(object->methodIntCalled(), false);
373 emit object->basicSignal();
374 QCOMPARE(object->methodCalled(), true);
375 QCOMPARE(object->methodIntCalled(), false);
380 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
381 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
382 QVERIFY(object != 0);
383 QCOMPARE(object->methodCalled(), false);
384 QCOMPARE(object->methodIntCalled(), false);
385 emit object->basicSignal();
386 QCOMPARE(object->methodCalled(), false);
387 QCOMPARE(object->methodIntCalled(), true);
392 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
393 QObject *object = component.create();
394 QVERIFY(object != 0);
395 QCOMPARE(object->property("test").toInt(), 19);
400 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
401 QObject *object = component.create();
402 QVERIFY(object != 0);
403 QCOMPARE(object->property("test").toInt(), 19);
404 QCOMPARE(object->property("test2").toInt(), 17);
405 QCOMPARE(object->property("test3").toInt(), 16);
410 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
411 QObject *object = component.create();
412 QVERIFY(object != 0);
413 QCOMPARE(object->property("test").toInt(), 9);
418 void tst_qdeclarativeecmascript::bindingLoop()
420 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
421 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
422 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
423 QObject *object = component.create();
424 QVERIFY(object != 0);
428 void tst_qdeclarativeecmascript::basicExpressions_data()
430 QTest::addColumn<QString>("expression");
431 QTest::addColumn<QVariant>("result");
432 QTest::addColumn<bool>("nest");
434 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
435 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
436 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
437 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
438 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
439 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
440 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
441 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
442 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
443 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
444 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
445 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
446 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
447 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
448 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
449 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
450 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
451 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
452 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
455 void tst_qdeclarativeecmascript::basicExpressions()
457 QFETCH(QString, expression);
458 QFETCH(QVariant, result);
464 MyDefaultObject1 default1;
465 MyDefaultObject3 default3;
466 object1.setStringProperty("Object1");
467 object2.setStringProperty("Object2");
468 object3.setStringProperty("Object3");
470 QDeclarativeContext context(engine.rootContext());
471 QDeclarativeContext nestedContext(&context);
473 context.setContextObject(&default1);
474 context.setContextProperty("a", QVariant(1944));
475 context.setContextProperty("b", QVariant("Milk"));
476 context.setContextProperty("object", &object1);
477 context.setContextProperty("objectOverride", &object2);
478 nestedContext.setContextObject(&default3);
479 nestedContext.setContextProperty("b", QVariant("Cow"));
480 nestedContext.setContextProperty("objectOverride", &object3);
481 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
483 MyExpression expr(nest?&nestedContext:&context, expression);
484 QCOMPARE(expr.evaluate(), result);
487 void tst_qdeclarativeecmascript::arrayExpressions()
493 QDeclarativeContext context(engine.rootContext());
494 context.setContextProperty("a", &obj1);
495 context.setContextProperty("b", &obj2);
496 context.setContextProperty("c", &obj3);
498 MyExpression expr(&context, "[a, b, c, 10]");
499 QVariant result = expr.evaluate();
500 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
501 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
502 QCOMPARE(list.count(), 4);
503 QCOMPARE(list.at(0), &obj1);
504 QCOMPARE(list.at(1), &obj2);
505 QCOMPARE(list.at(2), &obj3);
506 QCOMPARE(list.at(3), (QObject *)0);
509 // Tests that modifying a context property will reevaluate expressions
510 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
512 QDeclarativeContext context(engine.rootContext());
515 MyQmlObject *object3 = new MyQmlObject;
517 object1.setStringProperty("Hello");
518 object2.setStringProperty("World");
520 context.setContextProperty("testProp", QVariant(1));
521 context.setContextProperty("testObj", &object1);
522 context.setContextProperty("testObj2", object3);
525 MyExpression expr(&context, "testProp + 1");
526 QCOMPARE(expr.changed, false);
527 QCOMPARE(expr.evaluate(), QVariant(2));
529 context.setContextProperty("testProp", QVariant(2));
530 QCOMPARE(expr.changed, true);
531 QCOMPARE(expr.evaluate(), QVariant(3));
535 MyExpression expr(&context, "testProp + testProp + testProp");
536 QCOMPARE(expr.changed, false);
537 QCOMPARE(expr.evaluate(), QVariant(6));
539 context.setContextProperty("testProp", QVariant(4));
540 QCOMPARE(expr.changed, true);
541 QCOMPARE(expr.evaluate(), QVariant(12));
545 MyExpression expr(&context, "testObj.stringProperty");
546 QCOMPARE(expr.changed, false);
547 QCOMPARE(expr.evaluate(), QVariant("Hello"));
549 context.setContextProperty("testObj", &object2);
550 QCOMPARE(expr.changed, true);
551 QCOMPARE(expr.evaluate(), QVariant("World"));
555 MyExpression expr(&context, "testObj.stringProperty /**/");
556 QCOMPARE(expr.changed, false);
557 QCOMPARE(expr.evaluate(), QVariant("World"));
559 context.setContextProperty("testObj", &object1);
560 QCOMPARE(expr.changed, true);
561 QCOMPARE(expr.evaluate(), QVariant("Hello"));
565 MyExpression expr(&context, "testObj2");
566 QCOMPARE(expr.changed, false);
567 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
573 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
575 QDeclarativeContext context(engine.rootContext());
579 context.setContextProperty("testObj", &object1);
581 object1.setStringProperty(QLatin1String("Hello"));
582 object2.setStringProperty(QLatin1String("Dog"));
583 object3.setStringProperty(QLatin1String("Cat"));
586 MyExpression expr(&context, "testObj.stringProperty");
587 QCOMPARE(expr.changed, false);
588 QCOMPARE(expr.evaluate(), QVariant("Hello"));
590 object1.setStringProperty(QLatin1String("World"));
591 QCOMPARE(expr.changed, true);
592 QCOMPARE(expr.evaluate(), QVariant("World"));
596 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
597 QCOMPARE(expr.changed, false);
598 QCOMPARE(expr.evaluate(), QVariant());
600 object1.setObjectProperty(&object2);
601 QCOMPARE(expr.changed, true);
602 expr.changed = false;
603 QCOMPARE(expr.evaluate(), QVariant("Dog"));
605 object1.setObjectProperty(&object3);
606 QCOMPARE(expr.changed, true);
607 expr.changed = false;
608 QCOMPARE(expr.evaluate(), QVariant("Cat"));
610 object1.setObjectProperty(0);
611 QCOMPARE(expr.changed, true);
612 expr.changed = false;
613 QCOMPARE(expr.evaluate(), QVariant());
615 object1.setObjectProperty(&object3);
616 QCOMPARE(expr.changed, true);
617 expr.changed = false;
618 QCOMPARE(expr.evaluate(), QVariant("Cat"));
620 object3.setStringProperty("Donkey");
621 QCOMPARE(expr.changed, true);
622 expr.changed = false;
623 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
627 void tst_qdeclarativeecmascript::deferredProperties()
629 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
630 MyDeferredObject *object =
631 qobject_cast<MyDeferredObject *>(component.create());
632 QVERIFY(object != 0);
633 QCOMPARE(object->value(), 0);
634 QVERIFY(object->objectProperty() == 0);
635 QVERIFY(object->objectProperty2() != 0);
636 qmlExecuteDeferred(object);
637 QCOMPARE(object->value(), 10);
638 QVERIFY(object->objectProperty() != 0);
639 MyQmlObject *qmlObject =
640 qobject_cast<MyQmlObject *>(object->objectProperty());
641 QVERIFY(qmlObject != 0);
642 QCOMPARE(qmlObject->value(), 10);
643 object->setValue(19);
644 QCOMPARE(qmlObject->value(), 19);
649 // Check errors on deferred properties are correctly emitted
650 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
652 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
653 MyDeferredObject *object =
654 qobject_cast<MyDeferredObject *>(component.create());
655 QVERIFY(object != 0);
656 QCOMPARE(object->value(), 0);
657 QVERIFY(object->objectProperty() == 0);
658 QVERIFY(object->objectProperty2() == 0);
660 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
661 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
663 qmlExecuteDeferred(object);
668 void tst_qdeclarativeecmascript::extensionObjects()
670 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
671 MyExtendedObject *object =
672 qobject_cast<MyExtendedObject *>(component.create());
673 QVERIFY(object != 0);
674 QCOMPARE(object->baseProperty(), 13);
675 QCOMPARE(object->coreProperty(), 9);
676 object->setProperty("extendedProperty", QVariant(11));
677 object->setProperty("baseExtendedProperty", QVariant(92));
678 QCOMPARE(object->coreProperty(), 11);
679 QCOMPARE(object->baseProperty(), 92);
681 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
683 QCOMPARE(nested->baseProperty(), 13);
684 QCOMPARE(nested->coreProperty(), 9);
685 nested->setProperty("extendedProperty", QVariant(11));
686 nested->setProperty("baseExtendedProperty", QVariant(92));
687 QCOMPARE(nested->coreProperty(), 11);
688 QCOMPARE(nested->baseProperty(), 92);
693 void tst_qdeclarativeecmascript::overrideExtensionProperties()
695 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
696 OverrideDefaultPropertyObject *object =
697 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
698 QVERIFY(object != 0);
699 QVERIFY(object->secondProperty() != 0);
700 QVERIFY(object->firstProperty() == 0);
705 void tst_qdeclarativeecmascript::attachedProperties()
708 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
709 QObject *object = component.create();
710 QVERIFY(object != 0);
711 QCOMPARE(object->property("a").toInt(), 19);
712 QCOMPARE(object->property("b").toInt(), 19);
713 QCOMPARE(object->property("c").toInt(), 19);
714 QCOMPARE(object->property("d").toInt(), 19);
719 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
720 QObject *object = component.create();
721 QVERIFY(object != 0);
722 QCOMPARE(object->property("a").toInt(), 26);
723 QCOMPARE(object->property("b").toInt(), 26);
724 QCOMPARE(object->property("c").toInt(), 26);
725 QCOMPARE(object->property("d").toInt(), 26);
731 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
732 QObject *object = component.create();
733 QVERIFY(object != 0);
735 QMetaObject::invokeMethod(object, "writeValue2");
737 MyQmlAttachedObject *attached =
738 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
739 QVERIFY(attached != 0);
741 QCOMPARE(attached->value2(), 9);
746 void tst_qdeclarativeecmascript::enums()
750 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
751 QObject *object = component.create();
752 QVERIFY(object != 0);
754 QCOMPARE(object->property("a").toInt(), 0);
755 QCOMPARE(object->property("b").toInt(), 1);
756 QCOMPARE(object->property("c").toInt(), 2);
757 QCOMPARE(object->property("d").toInt(), 3);
758 QCOMPARE(object->property("e").toInt(), 0);
759 QCOMPARE(object->property("f").toInt(), 1);
760 QCOMPARE(object->property("g").toInt(), 2);
761 QCOMPARE(object->property("h").toInt(), 3);
762 QCOMPARE(object->property("i").toInt(), 19);
763 QCOMPARE(object->property("j").toInt(), 19);
767 // Non-existent enums
769 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
771 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
772 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
773 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
774 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
776 QObject *object = component.create();
777 QVERIFY(object != 0);
778 QCOMPARE(object->property("a").toInt(), 0);
779 QCOMPARE(object->property("b").toInt(), 0);
785 void tst_qdeclarativeecmascript::valueTypeFunctions()
787 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
788 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
790 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
791 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
797 Tests that writing a constant to a property with a binding on it disables the
800 void tst_qdeclarativeecmascript::constantsOverrideBindings()
804 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
805 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
806 QVERIFY(object != 0);
808 QCOMPARE(object->property("c2").toInt(), 0);
809 object->setProperty("c1", QVariant(9));
810 QCOMPARE(object->property("c2").toInt(), 9);
812 emit object->basicSignal();
814 QCOMPARE(object->property("c2").toInt(), 13);
815 object->setProperty("c1", QVariant(8));
816 QCOMPARE(object->property("c2").toInt(), 13);
821 // During construction
823 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
824 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
825 QVERIFY(object != 0);
827 QCOMPARE(object->property("c1").toInt(), 0);
828 QCOMPARE(object->property("c2").toInt(), 10);
829 object->setProperty("c1", QVariant(9));
830 QCOMPARE(object->property("c1").toInt(), 9);
831 QCOMPARE(object->property("c2").toInt(), 10);
839 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
840 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
841 QVERIFY(object != 0);
843 QCOMPARE(object->property("c2").toInt(), 0);
844 object->setProperty("c1", QVariant(9));
845 QCOMPARE(object->property("c2").toInt(), 9);
847 object->setProperty("c2", QVariant(13));
848 QCOMPARE(object->property("c2").toInt(), 13);
849 object->setProperty("c1", QVariant(7));
850 QCOMPARE(object->property("c1").toInt(), 7);
851 QCOMPARE(object->property("c2").toInt(), 13);
859 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
860 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
861 QVERIFY(object != 0);
863 QCOMPARE(object->property("c1").toInt(), 0);
864 QCOMPARE(object->property("c3").toInt(), 10);
865 object->setProperty("c1", QVariant(9));
866 QCOMPARE(object->property("c1").toInt(), 9);
867 QCOMPARE(object->property("c3").toInt(), 10);
874 Tests that assigning a binding to a property that already has a binding causes
875 the original binding to be disabled.
877 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
879 QDeclarativeComponent component(&engine,
880 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
881 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
882 QVERIFY(object != 0);
884 QCOMPARE(object->property("c1").toInt(), 0);
885 QCOMPARE(object->property("c2").toInt(), 0);
886 QCOMPARE(object->property("c3").toInt(), 0);
888 object->setProperty("c1", QVariant(9));
889 QCOMPARE(object->property("c1").toInt(), 9);
890 QCOMPARE(object->property("c2").toInt(), 0);
891 QCOMPARE(object->property("c3").toInt(), 0);
893 object->setProperty("c3", QVariant(8));
894 QCOMPARE(object->property("c1").toInt(), 9);
895 QCOMPARE(object->property("c2").toInt(), 8);
896 QCOMPARE(object->property("c3").toInt(), 8);
902 Access a non-existent attached object.
904 Tests for a regression where this used to crash.
906 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
908 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
910 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
911 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
913 QObject *object = component.create();
914 QVERIFY(object != 0);
919 void tst_qdeclarativeecmascript::scope()
922 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
923 QObject *object = component.create();
924 QVERIFY(object != 0);
926 QCOMPARE(object->property("test1").toInt(), 1);
927 QCOMPARE(object->property("test2").toInt(), 2);
928 QCOMPARE(object->property("test3").toString(), QString("1Test"));
929 QCOMPARE(object->property("test4").toString(), QString("2Test"));
930 QCOMPARE(object->property("test5").toInt(), 1);
931 QCOMPARE(object->property("test6").toInt(), 1);
932 QCOMPARE(object->property("test7").toInt(), 2);
933 QCOMPARE(object->property("test8").toInt(), 2);
934 QCOMPARE(object->property("test9").toInt(), 1);
935 QCOMPARE(object->property("test10").toInt(), 3);
941 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
942 QObject *object = component.create();
943 QVERIFY(object != 0);
945 QCOMPARE(object->property("test1").toInt(), 19);
946 QCOMPARE(object->property("test2").toInt(), 19);
947 QCOMPARE(object->property("test3").toInt(), 14);
948 QCOMPARE(object->property("test4").toInt(), 14);
949 QCOMPARE(object->property("test5").toInt(), 24);
950 QCOMPARE(object->property("test6").toInt(), 24);
956 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
957 QObject *object = component.create();
958 QVERIFY(object != 0);
960 QCOMPARE(object->property("test1").toBool(), true);
961 QCOMPARE(object->property("test2").toBool(), true);
962 QCOMPARE(object->property("test3").toBool(), true);
967 // Signal argument scope
969 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
970 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
971 QVERIFY(object != 0);
973 QCOMPARE(object->property("test").toInt(), 0);
974 QCOMPARE(object->property("test2").toString(), QString());
976 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
978 QCOMPARE(object->property("test").toInt(), 13);
979 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
985 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
986 QObject *object = component.create();
987 QVERIFY(object != 0);
989 QCOMPARE(object->property("test1").toBool(), true);
990 QCOMPARE(object->property("test2").toBool(), true);
996 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
997 QObject *object = component.create();
998 QVERIFY(object != 0);
1000 QCOMPARE(object->property("test").toBool(), true);
1006 // In 4.7, non-library javascript files that had no imports shared the imports of their
1007 // importing context
1008 void tst_qdeclarativeecmascript::importScope()
1010 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1011 QObject *o = component.create();
1014 QCOMPARE(o->property("test").toInt(), 240);
1020 Tests that "any" type passes through a synthesized signal parameter. This
1021 is essentially a test of QDeclarativeMetaType::copy()
1023 void tst_qdeclarativeecmascript::signalParameterTypes()
1025 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1026 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1027 QVERIFY(object != 0);
1029 emit object->basicSignal();
1031 QCOMPARE(object->property("intProperty").toInt(), 10);
1032 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1033 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1034 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1035 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1036 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1042 Test that two JS objects for the same QObject compare as equal.
1044 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1046 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1047 QObject *object = component.create();
1048 QVERIFY(object != 0);
1050 QCOMPARE(object->property("test1").toBool(), true);
1051 QCOMPARE(object->property("test2").toBool(), true);
1052 QCOMPARE(object->property("test3").toBool(), true);
1053 QCOMPARE(object->property("test4").toBool(), true);
1054 QCOMPARE(object->property("test5").toBool(), true);
1060 Confirm bindings and alias properties can coexist.
1062 Tests for a regression where the binding would not reevaluate.
1064 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1066 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1067 QObject *object = component.create();
1068 QVERIFY(object != 0);
1070 QCOMPARE(object->property("c2").toInt(), 3);
1071 QCOMPARE(object->property("c3").toInt(), 3);
1073 object->setProperty("c2", QVariant(19));
1075 QCOMPARE(object->property("c2").toInt(), 19);
1076 QCOMPARE(object->property("c3").toInt(), 19);
1082 Ensure that we can write undefined value to an alias property,
1083 and that the aliased property is reset correctly if possible.
1085 void tst_qdeclarativeecmascript::aliasPropertyReset()
1087 QObject *object = 0;
1089 // test that a manual write (of undefined) to a resettable aliased property succeeds
1090 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1091 object = c1.create();
1092 QVERIFY(object != 0);
1093 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1094 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1095 QMetaObject::invokeMethod(object, "resetAliased");
1096 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1097 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1100 // test that a manual write (of undefined) to a resettable alias property succeeds
1101 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1102 object = c2.create();
1103 QVERIFY(object != 0);
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1105 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1106 QMetaObject::invokeMethod(object, "resetAlias");
1107 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1108 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1111 // test that an alias to a bound property works correctly
1112 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1113 object = c3.create();
1114 QVERIFY(object != 0);
1115 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1116 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1117 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1118 QMetaObject::invokeMethod(object, "resetAlias");
1119 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1120 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1121 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1124 // test that a manual write (of undefined) to a resettable alias property
1125 // whose aliased property's object has been deleted, does not crash.
1126 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1127 object = c4.create();
1128 QVERIFY(object != 0);
1129 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1130 QObject *loader = object->findChild<QObject*>("loader");
1131 QVERIFY(loader != 0);
1133 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1134 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1135 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1136 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1137 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1140 // test that binding an alias property to an undefined value works correctly
1141 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1142 object = c5.create();
1143 QVERIFY(object != 0);
1144 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1147 // test that a manual write (of undefined) to a non-resettable property fails properly
1148 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1149 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1150 QDeclarativeComponent e1(&engine, url);
1151 object = e1.create();
1152 QVERIFY(object != 0);
1153 QCOMPARE(object->property("intAlias").value<int>(), 12);
1154 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1155 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1156 QMetaObject::invokeMethod(object, "resetAlias");
1157 QCOMPARE(object->property("intAlias").value<int>(), 12);
1158 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1162 void tst_qdeclarativeecmascript::dynamicCreation_data()
1164 QTest::addColumn<QString>("method");
1165 QTest::addColumn<QString>("createdName");
1167 QTest::newRow("One") << "createOne" << "objectOne";
1168 QTest::newRow("Two") << "createTwo" << "objectTwo";
1169 QTest::newRow("Three") << "createThree" << "objectThree";
1173 Test using createQmlObject to dynamically generate an item
1174 Also using createComponent is tested.
1176 void tst_qdeclarativeecmascript::dynamicCreation()
1178 QFETCH(QString, method);
1179 QFETCH(QString, createdName);
1181 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1182 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1183 QVERIFY(object != 0);
1185 QMetaObject::invokeMethod(object, method.toUtf8());
1186 QObject *created = object->objectProperty();
1188 QCOMPARE(created->objectName(), createdName);
1194 Tests the destroy function
1196 void tst_qdeclarativeecmascript::dynamicDestruction()
1199 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1200 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1201 QVERIFY(object != 0);
1202 QDeclarativeGuard<QObject> createdQmlObject = 0;
1204 QMetaObject::invokeMethod(object, "create");
1205 createdQmlObject = object->objectProperty();
1206 QVERIFY(createdQmlObject);
1207 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1209 QMetaObject::invokeMethod(object, "killOther");
1210 QVERIFY(createdQmlObject);
1211 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1212 QVERIFY(createdQmlObject);
1213 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1214 if (createdQmlObject) {
1216 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1219 QVERIFY(!createdQmlObject);
1221 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1222 QMetaObject::invokeMethod(object, "killMe");
1225 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1230 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1231 QObject *o = component.create();
1234 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1236 QMetaObject::invokeMethod(o, "create");
1238 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1240 QMetaObject::invokeMethod(o, "destroy");
1242 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1244 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1251 tests that id.toString() works
1253 void tst_qdeclarativeecmascript::objectToString()
1255 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1256 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1257 QVERIFY(object != 0);
1258 QMetaObject::invokeMethod(object, "testToString");
1259 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1260 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1266 tests that id.hasOwnProperty() works
1268 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1270 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1271 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1272 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1273 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1275 QDeclarativeComponent component(&engine, url);
1276 QObject *object = component.create();
1277 QVERIFY(object != 0);
1279 // test QObjects in QML
1280 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1281 QVERIFY(object->property("result").value<bool>() == true);
1282 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1283 QVERIFY(object->property("result").value<bool>() == false);
1285 // now test other types in QML
1286 QObject *child = object->findChild<QObject*>("typeObj");
1287 QVERIFY(child != 0);
1288 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1289 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1290 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1291 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1292 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1293 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1294 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1295 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1296 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1297 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1298 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1299 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1301 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1302 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1303 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1304 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1305 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1306 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1307 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1308 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1309 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1315 Tests bindings that indirectly cause their own deletion work.
1317 This test is best run under valgrind to ensure no invalid memory access occur.
1319 void tst_qdeclarativeecmascript::selfDeletingBinding()
1322 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1323 QObject *object = component.create();
1324 QVERIFY(object != 0);
1325 object->setProperty("triggerDelete", true);
1330 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1331 QObject *object = component.create();
1332 QVERIFY(object != 0);
1333 object->setProperty("triggerDelete", true);
1339 Test that extended object properties can be accessed.
1341 This test a regression where this used to crash. The issue was specificially
1342 for extended objects that did not include a synthesized meta object (so non-root
1343 and no synthesiszed properties).
1345 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1347 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1348 QObject *object = component.create();
1349 QVERIFY(object != 0);
1354 Test file/lineNumbers for binding/Script errors.
1356 void tst_qdeclarativeecmascript::scriptErrors()
1358 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1359 QString url = component.url().toString();
1361 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1362 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1363 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1364 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1365 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1366 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1367 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1368 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1370 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1371 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1372 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1373 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1374 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1375 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1376 QVERIFY(object != 0);
1378 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1379 emit object->basicSignal();
1381 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1382 emit object->anotherBasicSignal();
1384 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1385 emit object->thirdBasicSignal();
1391 Test file/lineNumbers for inline functions.
1393 void tst_qdeclarativeecmascript::functionErrors()
1395 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1396 QString url = component.url().toString();
1398 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1400 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1402 QObject *object = component.create();
1403 QVERIFY(object != 0);
1406 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1407 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1408 url = componentTwo.url().toString();
1409 object = componentTwo.create();
1410 QVERIFY(object != 0);
1412 QString srpname = object->property("srp_name").toString();
1414 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1415 QLatin1String(" is not a function");
1416 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1417 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1422 Test various errors that can occur when assigning a property from script
1424 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1426 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1428 QString url = component.url().toString();
1430 QObject *object = component.create();
1431 QVERIFY(object != 0);
1433 QCOMPARE(object->property("test1").toBool(), true);
1434 QCOMPARE(object->property("test2").toBool(), true);
1440 Test bindings still work when the reeval is triggered from within
1443 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1445 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1446 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1447 QVERIFY(object != 0);
1449 QCOMPARE(object->property("base").toReal(), 50.);
1450 QCOMPARE(object->property("test1").toReal(), 50.);
1451 QCOMPARE(object->property("test2").toReal(), 50.);
1453 object->basicSignal();
1455 QCOMPARE(object->property("base").toReal(), 200.);
1456 QCOMPARE(object->property("test1").toReal(), 200.);
1457 QCOMPARE(object->property("test2").toReal(), 200.);
1459 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1461 QCOMPARE(object->property("base").toReal(), 400.);
1462 QCOMPARE(object->property("test1").toReal(), 400.);
1463 QCOMPARE(object->property("test2").toReal(), 400.);
1469 Test that list properties can be iterated from ECMAScript
1471 void tst_qdeclarativeecmascript::listProperties()
1473 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1474 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1475 QVERIFY(object != 0);
1477 QCOMPARE(object->property("test1").toInt(), 21);
1478 QCOMPARE(object->property("test2").toInt(), 2);
1479 QCOMPARE(object->property("test3").toBool(), true);
1480 QCOMPARE(object->property("test4").toBool(), true);
1485 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1487 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1488 QString url = component.url().toString();
1490 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1492 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1493 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1494 QVERIFY(object != 0);
1496 QCOMPARE(object->property("test").toBool(), false);
1498 MyQmlObject object2;
1499 MyQmlObject object3;
1500 object2.setObjectProperty(&object3);
1501 object->setObjectProperty(&object2);
1503 QCOMPARE(object->property("test").toBool(), true);
1508 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1510 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1511 QString url = component.url().toString();
1513 QString warning = component.url().toString() + ":6: Error: JS exception";
1515 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1516 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1517 QVERIFY(object != 0);
1521 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1523 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1524 QString url = component.url().toString();
1526 QString warning = component.url().toString() + ":5: Error: JS exception";
1528 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1529 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1530 QVERIFY(object != 0);
1534 static int transientErrorsMsgCount = 0;
1535 static void transientErrorsMsgHandler(QtMsgType, const char *)
1537 ++transientErrorsMsgCount;
1540 // Check that transient binding errors are not displayed
1541 void tst_qdeclarativeecmascript::transientErrors()
1544 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1546 transientErrorsMsgCount = 0;
1547 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1549 QObject *object = component.create();
1550 QVERIFY(object != 0);
1552 qInstallMsgHandler(old);
1554 QCOMPARE(transientErrorsMsgCount, 0);
1559 // One binding erroring multiple times, but then resolving
1561 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1563 transientErrorsMsgCount = 0;
1564 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1566 QObject *object = component.create();
1567 QVERIFY(object != 0);
1569 qInstallMsgHandler(old);
1571 QCOMPARE(transientErrorsMsgCount, 0);
1577 // Check that errors during shutdown are minimized
1578 void tst_qdeclarativeecmascript::shutdownErrors()
1580 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1581 QObject *object = component.create();
1582 QVERIFY(object != 0);
1584 transientErrorsMsgCount = 0;
1585 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1589 qInstallMsgHandler(old);
1590 QCOMPARE(transientErrorsMsgCount, 0);
1593 void tst_qdeclarativeecmascript::compositePropertyType()
1595 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1596 QString messageFormat = QString(QLatin1String("hello world (%1:%2)")).arg(TEST_FILE("compositePropertyType.qml").toString()).arg(7);
1597 QTest::ignoreMessage(QtDebugMsg, qPrintable(messageFormat));
1598 QObject *object = qobject_cast<QObject *>(component.create());
1603 void tst_qdeclarativeecmascript::jsObject()
1605 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1606 QObject *object = component.create();
1607 QVERIFY(object != 0);
1609 QCOMPARE(object->property("test").toInt(), 92);
1614 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1617 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1618 QObject *object = component.create();
1619 QVERIFY(object != 0);
1621 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1623 object->setProperty("setUndefined", true);
1625 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1627 object->setProperty("setUndefined", false);
1629 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1634 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1635 QObject *object = component.create();
1636 QVERIFY(object != 0);
1638 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1640 QMetaObject::invokeMethod(object, "doReset");
1642 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1648 // Aliases to variant properties should work
1649 void tst_qdeclarativeecmascript::qtbug_22464()
1651 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1652 QObject *object = component.create();
1653 QVERIFY(object != 0);
1655 QCOMPARE(object->property("test").toBool(), true);
1660 void tst_qdeclarativeecmascript::qtbug_21580()
1662 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
1664 QObject *object = component.create();
1665 QVERIFY(object != 0);
1667 QCOMPARE(object->property("test").toBool(), true);
1673 void tst_qdeclarativeecmascript::bug1()
1675 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1676 QObject *object = component.create();
1677 QVERIFY(object != 0);
1679 QCOMPARE(object->property("test").toInt(), 14);
1681 object->setProperty("a", 11);
1683 QCOMPARE(object->property("test").toInt(), 3);
1685 object->setProperty("b", true);
1687 QCOMPARE(object->property("test").toInt(), 9);
1692 void tst_qdeclarativeecmascript::bug2()
1694 QDeclarativeComponent component(&engine);
1695 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1697 QObject *object = component.create();
1698 QVERIFY(object != 0);
1703 // Don't crash in createObject when the component has errors.
1704 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1706 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1707 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1708 QVERIFY(object != 0);
1710 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1711 QMetaObject::invokeMethod(object, "dontCrash");
1712 QObject *created = object->objectProperty();
1713 QVERIFY(created == 0);
1718 // ownership transferred to JS, ensure that GC runs the dtor
1719 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1722 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1724 // allow the engine to go out of scope too.
1726 QDeclarativeEngine dcoEngine;
1727 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1728 QObject *object = component.create();
1729 QVERIFY(object != 0);
1730 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1731 QVERIFY(mdcdo != 0);
1732 mdcdo->setDtorCount(&dtorCount);
1734 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1735 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1737 // we do this once manually, but it should be done automatically
1738 // when the engine goes out of scope (since it should gc in dtor)
1739 QMetaObject::invokeMethod(object, "performGc");
1742 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1748 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1749 QCOMPARE(dtorCount, expectedDtorCount);
1753 void tst_qdeclarativeecmascript::regExpBug()
1755 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1756 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1757 QVERIFY(object != 0);
1758 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1762 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1764 QString functionSource = QLatin1String("(function(object) { return ") +
1765 QLatin1String(source) + QLatin1String(" })");
1767 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1770 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1771 if (function.IsEmpty())
1773 v8::Handle<v8::Value> args[] = { o };
1774 function->Call(engine->global(), 1, args);
1775 return tc.HasCaught();
1778 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1779 const char *source, v8::Handle<v8::Value> result)
1781 QString functionSource = QLatin1String("(function(object) { return ") +
1782 QLatin1String(source) + QLatin1String(" })");
1784 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1787 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1788 if (function.IsEmpty())
1790 v8::Handle<v8::Value> args[] = { o };
1792 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1797 return value->StrictEquals(result);
1800 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1803 QString functionSource = QLatin1String("(function(object) { return ") +
1804 QLatin1String(source) + QLatin1String(" })");
1806 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1808 return v8::Handle<v8::Value>();
1809 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1810 if (function.IsEmpty())
1811 return v8::Handle<v8::Value>();
1812 v8::Handle<v8::Value> args[] = { o };
1814 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1817 return v8::Handle<v8::Value>();
1821 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1822 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1823 #define EVALUATE(source) evaluate(engine, object, source)
1825 void tst_qdeclarativeecmascript::callQtInvokables()
1827 MyInvokableObject o;
1829 QDeclarativeEngine qmlengine;
1830 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1832 QV8Engine *engine = ep->v8engine();
1834 v8::HandleScope handle_scope;
1835 v8::Context::Scope scope(engine->context());
1837 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1839 // Non-existent methods
1841 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1842 QCOMPARE(o.error(), false);
1843 QCOMPARE(o.invoked(), -1);
1844 QCOMPARE(o.actuals().count(), 0);
1847 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1848 QCOMPARE(o.error(), false);
1849 QCOMPARE(o.invoked(), -1);
1850 QCOMPARE(o.actuals().count(), 0);
1852 // Insufficient arguments
1854 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1855 QCOMPARE(o.error(), false);
1856 QCOMPARE(o.invoked(), -1);
1857 QCOMPARE(o.actuals().count(), 0);
1860 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1861 QCOMPARE(o.error(), false);
1862 QCOMPARE(o.invoked(), -1);
1863 QCOMPARE(o.actuals().count(), 0);
1865 // Excessive arguments
1867 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1868 QCOMPARE(o.error(), false);
1869 QCOMPARE(o.invoked(), 8);
1870 QCOMPARE(o.actuals().count(), 1);
1871 QCOMPARE(o.actuals().at(0), QVariant(10));
1874 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1875 QCOMPARE(o.error(), false);
1876 QCOMPARE(o.invoked(), 9);
1877 QCOMPARE(o.actuals().count(), 2);
1878 QCOMPARE(o.actuals().at(0), QVariant(10));
1879 QCOMPARE(o.actuals().at(1), QVariant(11));
1881 // Test return types
1883 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1884 QCOMPARE(o.error(), false);
1885 QCOMPARE(o.invoked(), 0);
1886 QCOMPARE(o.actuals().count(), 0);
1889 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1890 QCOMPARE(o.error(), false);
1891 QCOMPARE(o.invoked(), 1);
1892 QCOMPARE(o.actuals().count(), 0);
1895 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1896 QCOMPARE(o.error(), false);
1897 QCOMPARE(o.invoked(), 2);
1898 QCOMPARE(o.actuals().count(), 0);
1902 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1903 QVERIFY(!ret.IsEmpty());
1904 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1905 QCOMPARE(o.error(), false);
1906 QCOMPARE(o.invoked(), 3);
1907 QCOMPARE(o.actuals().count(), 0);
1912 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1913 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1914 QCOMPARE(o.error(), false);
1915 QCOMPARE(o.invoked(), 4);
1916 QCOMPARE(o.actuals().count(), 0);
1920 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1921 QCOMPARE(o.error(), false);
1922 QCOMPARE(o.invoked(), 5);
1923 QCOMPARE(o.actuals().count(), 0);
1927 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1928 QVERIFY(ret->IsString());
1929 QCOMPARE(engine->toString(ret), QString("Hello world"));
1930 QCOMPARE(o.error(), false);
1931 QCOMPARE(o.invoked(), 6);
1932 QCOMPARE(o.actuals().count(), 0);
1936 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1937 QCOMPARE(o.error(), false);
1938 QCOMPARE(o.invoked(), 7);
1939 QCOMPARE(o.actuals().count(), 0);
1943 QVERIFY(EVALUATE_VALUE("object.method_int(94)", 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(94));
1950 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", 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(94));
1957 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1958 QCOMPARE(o.error(), false);
1959 QCOMPARE(o.invoked(), 8);
1960 QCOMPARE(o.actuals().count(), 1);
1961 QCOMPARE(o.actuals().at(0), QVariant(0));
1964 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1965 QCOMPARE(o.error(), false);
1966 QCOMPARE(o.invoked(), 8);
1967 QCOMPARE(o.actuals().count(), 1);
1968 QCOMPARE(o.actuals().at(0), QVariant(0));
1971 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1972 QCOMPARE(o.error(), false);
1973 QCOMPARE(o.invoked(), 8);
1974 QCOMPARE(o.actuals().count(), 1);
1975 QCOMPARE(o.actuals().at(0), QVariant(0));
1978 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1979 QCOMPARE(o.error(), false);
1980 QCOMPARE(o.invoked(), 8);
1981 QCOMPARE(o.actuals().count(), 1);
1982 QCOMPARE(o.actuals().at(0), QVariant(0));
1985 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1986 QCOMPARE(o.error(), false);
1987 QCOMPARE(o.invoked(), 9);
1988 QCOMPARE(o.actuals().count(), 2);
1989 QCOMPARE(o.actuals().at(0), QVariant(122));
1990 QCOMPARE(o.actuals().at(1), QVariant(9));
1993 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1994 QCOMPARE(o.error(), false);
1995 QCOMPARE(o.invoked(), 10);
1996 QCOMPARE(o.actuals().count(), 1);
1997 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2000 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2001 QCOMPARE(o.error(), false);
2002 QCOMPARE(o.invoked(), 10);
2003 QCOMPARE(o.actuals().count(), 1);
2004 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2007 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2008 QCOMPARE(o.error(), false);
2009 QCOMPARE(o.invoked(), 10);
2010 QCOMPARE(o.actuals().count(), 1);
2011 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2014 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2015 QCOMPARE(o.error(), false);
2016 QCOMPARE(o.invoked(), 10);
2017 QCOMPARE(o.actuals().count(), 1);
2018 QCOMPARE(o.actuals().at(0), QVariant(0));
2021 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2022 QCOMPARE(o.error(), false);
2023 QCOMPARE(o.invoked(), 10);
2024 QCOMPARE(o.actuals().count(), 1);
2025 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2028 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2029 QCOMPARE(o.error(), false);
2030 QCOMPARE(o.invoked(), 10);
2031 QCOMPARE(o.actuals().count(), 1);
2032 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2035 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2036 QCOMPARE(o.error(), false);
2037 QCOMPARE(o.invoked(), 11);
2038 QCOMPARE(o.actuals().count(), 1);
2039 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2042 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2043 QCOMPARE(o.error(), false);
2044 QCOMPARE(o.invoked(), 11);
2045 QCOMPARE(o.actuals().count(), 1);
2046 QCOMPARE(o.actuals().at(0), QVariant("19"));
2050 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2051 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2052 QCOMPARE(o.error(), false);
2053 QCOMPARE(o.invoked(), 11);
2054 QCOMPARE(o.actuals().count(), 1);
2055 QCOMPARE(o.actuals().at(0), QVariant(expected));
2059 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2060 QCOMPARE(o.error(), false);
2061 QCOMPARE(o.invoked(), 11);
2062 QCOMPARE(o.actuals().count(), 1);
2063 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2066 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2067 QCOMPARE(o.error(), false);
2068 QCOMPARE(o.invoked(), 11);
2069 QCOMPARE(o.actuals().count(), 1);
2070 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2073 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2074 QCOMPARE(o.error(), false);
2075 QCOMPARE(o.invoked(), 12);
2076 QCOMPARE(o.actuals().count(), 1);
2077 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2080 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2081 QCOMPARE(o.error(), false);
2082 QCOMPARE(o.invoked(), 12);
2083 QCOMPARE(o.actuals().count(), 1);
2084 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2087 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2088 QCOMPARE(o.error(), false);
2089 QCOMPARE(o.invoked(), 12);
2090 QCOMPARE(o.actuals().count(), 1);
2091 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2094 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2095 QCOMPARE(o.error(), false);
2096 QCOMPARE(o.invoked(), 12);
2097 QCOMPARE(o.actuals().count(), 1);
2098 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2101 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2102 QCOMPARE(o.error(), false);
2103 QCOMPARE(o.invoked(), 12);
2104 QCOMPARE(o.actuals().count(), 1);
2105 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2108 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2109 QCOMPARE(o.error(), false);
2110 QCOMPARE(o.invoked(), 12);
2111 QCOMPARE(o.actuals().count(), 1);
2112 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2115 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2116 QCOMPARE(o.error(), false);
2117 QCOMPARE(o.invoked(), 13);
2118 QCOMPARE(o.actuals().count(), 1);
2119 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2122 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2123 QCOMPARE(o.error(), false);
2124 QCOMPARE(o.invoked(), 13);
2125 QCOMPARE(o.actuals().count(), 1);
2126 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2129 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2130 QCOMPARE(o.error(), false);
2131 QCOMPARE(o.invoked(), 13);
2132 QCOMPARE(o.actuals().count(), 1);
2133 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2136 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2137 QCOMPARE(o.error(), false);
2138 QCOMPARE(o.invoked(), 13);
2139 QCOMPARE(o.actuals().count(), 1);
2140 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2143 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2144 QCOMPARE(o.error(), false);
2145 QCOMPARE(o.invoked(), 13);
2146 QCOMPARE(o.actuals().count(), 1);
2147 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2150 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2151 QCOMPARE(o.error(), false);
2152 QCOMPARE(o.invoked(), 14);
2153 QCOMPARE(o.actuals().count(), 1);
2154 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2157 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2158 QCOMPARE(o.error(), false);
2159 QCOMPARE(o.invoked(), 14);
2160 QCOMPARE(o.actuals().count(), 1);
2161 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2164 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2165 QCOMPARE(o.error(), false);
2166 QCOMPARE(o.invoked(), 14);
2167 QCOMPARE(o.actuals().count(), 1);
2168 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2171 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2172 QCOMPARE(o.error(), false);
2173 QCOMPARE(o.invoked(), 14);
2174 QCOMPARE(o.actuals().count(), 1);
2175 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2178 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2179 QCOMPARE(o.error(), false);
2180 QCOMPARE(o.invoked(), 15);
2181 QCOMPARE(o.actuals().count(), 2);
2182 QCOMPARE(o.actuals().at(0), QVariant(4));
2183 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2186 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2187 QCOMPARE(o.error(), false);
2188 QCOMPARE(o.invoked(), 15);
2189 QCOMPARE(o.actuals().count(), 2);
2190 QCOMPARE(o.actuals().at(0), QVariant(8));
2191 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2194 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2195 QCOMPARE(o.error(), false);
2196 QCOMPARE(o.invoked(), 15);
2197 QCOMPARE(o.actuals().count(), 2);
2198 QCOMPARE(o.actuals().at(0), QVariant(3));
2199 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2202 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2203 QCOMPARE(o.error(), false);
2204 QCOMPARE(o.invoked(), 15);
2205 QCOMPARE(o.actuals().count(), 2);
2206 QCOMPARE(o.actuals().at(0), QVariant(44));
2207 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2210 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2211 QCOMPARE(o.error(), false);
2212 QCOMPARE(o.invoked(), -1);
2213 QCOMPARE(o.actuals().count(), 0);
2216 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2217 QCOMPARE(o.error(), false);
2218 QCOMPARE(o.invoked(), 16);
2219 QCOMPARE(o.actuals().count(), 1);
2220 QCOMPARE(o.actuals().at(0), QVariant(10));
2223 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2224 QCOMPARE(o.error(), false);
2225 QCOMPARE(o.invoked(), 17);
2226 QCOMPARE(o.actuals().count(), 2);
2227 QCOMPARE(o.actuals().at(0), QVariant(10));
2228 QCOMPARE(o.actuals().at(1), QVariant(11));
2231 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2232 QCOMPARE(o.error(), false);
2233 QCOMPARE(o.invoked(), 18);
2234 QCOMPARE(o.actuals().count(), 1);
2235 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2238 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2239 QCOMPARE(o.error(), false);
2240 QCOMPARE(o.invoked(), 19);
2241 QCOMPARE(o.actuals().count(), 1);
2242 QCOMPARE(o.actuals().at(0), QVariant(9));
2245 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2246 QCOMPARE(o.error(), false);
2247 QCOMPARE(o.invoked(), 20);
2248 QCOMPARE(o.actuals().count(), 2);
2249 QCOMPARE(o.actuals().at(0), QVariant(10));
2250 QCOMPARE(o.actuals().at(1), QVariant(19));
2253 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2254 QCOMPARE(o.error(), false);
2255 QCOMPARE(o.invoked(), 20);
2256 QCOMPARE(o.actuals().count(), 2);
2257 QCOMPARE(o.actuals().at(0), QVariant(10));
2258 QCOMPARE(o.actuals().at(1), QVariant(13));
2261 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2262 QCOMPARE(o.error(), false);
2263 QCOMPARE(o.invoked(), -3);
2264 QCOMPARE(o.actuals().count(), 1);
2265 QCOMPARE(o.actuals().at(0), QVariant(9));
2268 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2269 QCOMPARE(o.error(), false);
2270 QCOMPARE(o.invoked(), 21);
2271 QCOMPARE(o.actuals().count(), 2);
2272 QCOMPARE(o.actuals().at(0), QVariant(9));
2273 QCOMPARE(o.actuals().at(1), QVariant());
2276 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2277 QCOMPARE(o.error(), false);
2278 QCOMPARE(o.invoked(), 21);
2279 QCOMPARE(o.actuals().count(), 2);
2280 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2281 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2284 // QTBUG-13047 (check that you can pass registered object types as args)
2285 void tst_qdeclarativeecmascript::invokableObjectArg()
2287 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2289 QObject *o = component.create();
2291 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2293 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2298 // QTBUG-13047 (check that you can return registered object types from methods)
2299 void tst_qdeclarativeecmascript::invokableObjectRet()
2301 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2303 QObject *o = component.create();
2305 QCOMPARE(o->property("test").toBool(), true);
2310 void tst_qdeclarativeecmascript::listToVariant()
2312 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2314 MyQmlContainer container;
2316 QDeclarativeContext context(engine.rootContext());
2317 context.setContextObject(&container);
2319 QObject *object = component.create(&context);
2320 QVERIFY(object != 0);
2322 QVariant v = object->property("test");
2323 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2324 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2330 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2331 void tst_qdeclarativeecmascript::listAssignment()
2333 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2334 QObject *obj = component.create();
2335 QCOMPARE(obj->property("list1length").toInt(), 2);
2336 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2337 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2338 QCOMPARE(list1.count(&list1), list2.count(&list2));
2339 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2340 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2345 void tst_qdeclarativeecmascript::multiEngineObject()
2348 obj.setStringProperty("Howdy planet");
2350 QDeclarativeEngine e1;
2351 e1.rootContext()->setContextProperty("thing", &obj);
2352 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2354 QDeclarativeEngine e2;
2355 e2.rootContext()->setContextProperty("thing", &obj);
2356 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2358 QObject *o1 = c1.create();
2359 QObject *o2 = c2.create();
2361 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2362 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2368 // Test that references to QObjects are cleanup when the object is destroyed
2369 void tst_qdeclarativeecmascript::deletedObject()
2371 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2373 QObject *object = component.create();
2375 QCOMPARE(object->property("test1").toBool(), true);
2376 QCOMPARE(object->property("test2").toBool(), true);
2377 QCOMPARE(object->property("test3").toBool(), true);
2378 QCOMPARE(object->property("test4").toBool(), true);
2383 void tst_qdeclarativeecmascript::attachedPropertyScope()
2385 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2387 QObject *object = component.create();
2388 QVERIFY(object != 0);
2390 MyQmlAttachedObject *attached =
2391 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2392 QVERIFY(attached != 0);
2394 QCOMPARE(object->property("value2").toInt(), 0);
2396 attached->emitMySignal();
2398 QCOMPARE(object->property("value2").toInt(), 9);
2403 void tst_qdeclarativeecmascript::scriptConnect()
2406 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2408 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2409 QVERIFY(object != 0);
2411 QCOMPARE(object->property("test").toBool(), false);
2412 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2413 QCOMPARE(object->property("test").toBool(), true);
2419 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2421 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2422 QVERIFY(object != 0);
2424 QCOMPARE(object->property("test").toBool(), false);
2425 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2426 QCOMPARE(object->property("test").toBool(), true);
2432 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2434 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2435 QVERIFY(object != 0);
2437 QCOMPARE(object->property("test").toBool(), false);
2438 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2439 QCOMPARE(object->property("test").toBool(), true);
2445 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2447 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2448 QVERIFY(object != 0);
2450 QCOMPARE(object->methodCalled(), false);
2451 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2452 QCOMPARE(object->methodCalled(), true);
2458 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2460 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2461 QVERIFY(object != 0);
2463 QCOMPARE(object->methodCalled(), false);
2464 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2465 QCOMPARE(object->methodCalled(), true);
2471 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2473 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2474 QVERIFY(object != 0);
2476 QCOMPARE(object->property("test").toInt(), 0);
2477 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2478 QCOMPARE(object->property("test").toInt(), 2);
2484 void tst_qdeclarativeecmascript::scriptDisconnect()
2487 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2489 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2490 QVERIFY(object != 0);
2492 QCOMPARE(object->property("test").toInt(), 0);
2493 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2494 QCOMPARE(object->property("test").toInt(), 1);
2495 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2496 QCOMPARE(object->property("test").toInt(), 2);
2497 emit object->basicSignal();
2498 QCOMPARE(object->property("test").toInt(), 2);
2499 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2500 QCOMPARE(object->property("test").toInt(), 2);
2506 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2508 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2509 QVERIFY(object != 0);
2511 QCOMPARE(object->property("test").toInt(), 0);
2512 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2513 QCOMPARE(object->property("test").toInt(), 1);
2514 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2515 QCOMPARE(object->property("test").toInt(), 2);
2516 emit object->basicSignal();
2517 QCOMPARE(object->property("test").toInt(), 2);
2518 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2519 QCOMPARE(object->property("test").toInt(), 2);
2525 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2527 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2528 QVERIFY(object != 0);
2530 QCOMPARE(object->property("test").toInt(), 0);
2531 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2532 QCOMPARE(object->property("test").toInt(), 1);
2533 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2534 QCOMPARE(object->property("test").toInt(), 2);
2535 emit object->basicSignal();
2536 QCOMPARE(object->property("test").toInt(), 2);
2537 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2538 QCOMPARE(object->property("test").toInt(), 3);
2543 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2545 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2546 QVERIFY(object != 0);
2548 QCOMPARE(object->property("test").toInt(), 0);
2549 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2550 QCOMPARE(object->property("test").toInt(), 1);
2551 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2552 QCOMPARE(object->property("test").toInt(), 2);
2553 emit object->basicSignal();
2554 QCOMPARE(object->property("test").toInt(), 2);
2555 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2556 QCOMPARE(object->property("test").toInt(), 3);
2562 class OwnershipObject : public QObject
2566 OwnershipObject() { object = new QObject; }
2568 QPointer<QObject> object;
2571 QObject *getObject() { return object; }
2574 void tst_qdeclarativeecmascript::ownership()
2576 OwnershipObject own;
2577 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2578 context->setContextObject(&own);
2581 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2583 QVERIFY(own.object != 0);
2585 QObject *object = component.create(context);
2587 engine.collectGarbage();
2589 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2591 QVERIFY(own.object == 0);
2596 own.object = new QObject(&own);
2599 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2601 QVERIFY(own.object != 0);
2603 QObject *object = component.create(context);
2605 engine.collectGarbage();
2607 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2609 QVERIFY(own.object != 0);
2617 class CppOwnershipReturnValue : public QObject
2621 CppOwnershipReturnValue() : value(0) {}
2622 ~CppOwnershipReturnValue() { delete value; }
2624 Q_INVOKABLE QObject *create() {
2625 value = new QObject;
2626 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2630 Q_INVOKABLE MyQmlObject *createQmlObject() {
2631 MyQmlObject *rv = new MyQmlObject;
2636 QPointer<QObject> value;
2640 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2641 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2643 CppOwnershipReturnValue source;
2646 QDeclarativeEngine engine;
2647 engine.rootContext()->setContextProperty("source", &source);
2649 QVERIFY(source.value == 0);
2651 QDeclarativeComponent component(&engine);
2652 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2654 QObject *object = component.create();
2656 QVERIFY(object != 0);
2657 QVERIFY(source.value != 0);
2662 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2664 QVERIFY(source.value != 0);
2668 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2670 CppOwnershipReturnValue source;
2673 QDeclarativeEngine engine;
2674 engine.rootContext()->setContextProperty("source", &source);
2676 QVERIFY(source.value == 0);
2678 QDeclarativeComponent component(&engine);
2679 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2681 QObject *object = component.create();
2683 QVERIFY(object != 0);
2684 QVERIFY(source.value != 0);
2689 engine.collectGarbage();
2690 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2692 QVERIFY(source.value == 0);
2695 class QListQObjectMethodsObject : public QObject
2699 QListQObjectMethodsObject() {
2700 m_objects.append(new MyQmlObject());
2701 m_objects.append(new MyQmlObject());
2704 ~QListQObjectMethodsObject() {
2705 qDeleteAll(m_objects);
2709 QList<QObject *> getObjects() { return m_objects; }
2712 QList<QObject *> m_objects;
2715 // Tests that returning a QList<QObject*> from a method works
2716 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2718 QListQObjectMethodsObject obj;
2719 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2720 context->setContextObject(&obj);
2722 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2724 QObject *object = component.create(context);
2726 QCOMPARE(object->property("test").toInt(), 2);
2727 QCOMPARE(object->property("test2").toBool(), true);
2734 void tst_qdeclarativeecmascript::strictlyEquals()
2736 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2738 QObject *object = component.create();
2739 QVERIFY(object != 0);
2741 QCOMPARE(object->property("test1").toBool(), true);
2742 QCOMPARE(object->property("test2").toBool(), true);
2743 QCOMPARE(object->property("test3").toBool(), true);
2744 QCOMPARE(object->property("test4").toBool(), true);
2745 QCOMPARE(object->property("test5").toBool(), true);
2746 QCOMPARE(object->property("test6").toBool(), true);
2747 QCOMPARE(object->property("test7").toBool(), true);
2748 QCOMPARE(object->property("test8").toBool(), true);
2753 void tst_qdeclarativeecmascript::compiled()
2755 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2757 QObject *object = component.create();
2758 QVERIFY(object != 0);
2760 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2761 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2762 QCOMPARE(object->property("test3").toBool(), true);
2763 QCOMPARE(object->property("test4").toBool(), false);
2764 QCOMPARE(object->property("test5").toBool(), false);
2765 QCOMPARE(object->property("test6").toBool(), true);
2767 QCOMPARE(object->property("test7").toInt(), 185);
2768 QCOMPARE(object->property("test8").toInt(), 167);
2769 QCOMPARE(object->property("test9").toBool(), true);
2770 QCOMPARE(object->property("test10").toBool(), false);
2771 QCOMPARE(object->property("test11").toBool(), false);
2772 QCOMPARE(object->property("test12").toBool(), true);
2774 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2775 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2776 QCOMPARE(object->property("test15").toBool(), false);
2777 QCOMPARE(object->property("test16").toBool(), true);
2779 QCOMPARE(object->property("test17").toInt(), 5);
2780 QCOMPARE(object->property("test18").toReal(), qreal(176));
2781 QCOMPARE(object->property("test19").toInt(), 7);
2782 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2783 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2784 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2785 QCOMPARE(object->property("test23").toBool(), true);
2786 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2787 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2792 // Test that numbers assigned in bindings as strings work consistently
2793 void tst_qdeclarativeecmascript::numberAssignment()
2795 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2797 QObject *object = component.create();
2798 QVERIFY(object != 0);
2800 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2801 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2802 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2803 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2804 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2806 QCOMPARE(object->property("test5"), QVariant((int)7));
2807 QCOMPARE(object->property("test6"), QVariant((int)7));
2808 QCOMPARE(object->property("test7"), QVariant((int)6));
2809 QCOMPARE(object->property("test8"), QVariant((int)6));
2811 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2812 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2813 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2814 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2819 void tst_qdeclarativeecmascript::propertySplicing()
2821 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2823 QObject *object = component.create();
2824 QVERIFY(object != 0);
2826 QCOMPARE(object->property("test").toBool(), true);
2832 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2834 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2836 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2837 QVERIFY(object != 0);
2839 MyQmlObject::MyType type;
2840 type.value = 0x8971123;
2841 emit object->signalWithUnknownType(type);
2843 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2845 QCOMPARE(result.value, type.value);
2851 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2853 QTest::addColumn<QString>("expression");
2854 QTest::addColumn<QString>("compare");
2856 QString compareStrict("(function(a, b) { return a === b; })");
2857 QTest::newRow("true") << "true" << compareStrict;
2858 QTest::newRow("undefined") << "undefined" << compareStrict;
2859 QTest::newRow("null") << "null" << compareStrict;
2860 QTest::newRow("123") << "123" << compareStrict;
2861 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2863 QString comparePropertiesStrict(
2865 " if (typeof b != 'object')"
2867 " var props = Object.getOwnPropertyNames(b);"
2868 " for (var i = 0; i < props.length; ++i) {"
2869 " var p = props[i];"
2870 " return arguments.callee(a[p], b[p]);"
2873 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2874 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2877 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2879 QFETCH(QString, expression);
2880 QFETCH(QString, compare);
2882 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2883 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2884 QVERIFY(object != 0);
2886 QJSValue value = engine.evaluate(expression);
2887 QVERIFY(!engine.hasUncaughtException());
2888 object->setProperty("expression", expression);
2889 object->setProperty("compare", compare);
2890 object->setProperty("pass", false);
2892 emit object->signalWithVariant(QVariant::fromValue(value));
2893 QVERIFY(object->property("pass").toBool());
2896 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2898 signalWithJSValueInVariant_data();
2901 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2903 QFETCH(QString, expression);
2904 QFETCH(QString, compare);
2906 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2907 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2908 QVERIFY(object != 0);
2911 QJSValue value = engine2.evaluate(expression);
2912 QVERIFY(!engine2.hasUncaughtException());
2913 object->setProperty("expression", expression);
2914 object->setProperty("compare", compare);
2915 object->setProperty("pass", false);
2917 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2918 emit object->signalWithVariant(QVariant::fromValue(value));
2919 QVERIFY(!object->property("pass").toBool());
2922 void tst_qdeclarativeecmascript::moduleApi_data()
2924 QTest::addColumn<QUrl>("testfile");
2925 QTest::addColumn<QString>("errorMessage");
2926 QTest::addColumn<QStringList>("warningMessages");
2927 QTest::addColumn<QStringList>("readProperties");
2928 QTest::addColumn<QVariantList>("readExpectedValues");
2929 QTest::addColumn<QStringList>("writeProperties");
2930 QTest::addColumn<QVariantList>("writeValues");
2931 QTest::addColumn<QStringList>("readBackProperties");
2932 QTest::addColumn<QVariantList>("readBackExpectedValues");
2934 QTest::newRow("qobject, register + read + method")
2935 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2938 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2939 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2940 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2946 QTest::newRow("script, register + read")
2947 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2950 << (QStringList() << "scriptTest")
2951 << (QVariantList() << 13)
2957 QTest::newRow("qobject, caching + read")
2958 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2961 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2962 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2968 QTest::newRow("script, caching + read")
2969 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2972 << (QStringList() << "scriptTest")
2973 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2979 QTest::newRow("qobject, writing + readonly constraints")
2980 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2982 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2983 << (QStringList() << "readOnlyProperty" << "writableProperty")
2984 << (QVariantList() << 20 << 50)
2985 << (QStringList() << "firstProperty" << "writableProperty")
2986 << (QVariantList() << 30 << 30)
2987 << (QStringList() << "readOnlyProperty" << "writableProperty")
2988 << (QVariantList() << 20 << 30);
2990 QTest::newRow("script, writing + readonly constraints")
2991 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2993 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2994 << (QStringList() << "readBack" << "unchanged")
2995 << (QVariantList() << 13 << 42)
2996 << (QStringList() << "firstProperty" << "secondProperty")
2997 << (QVariantList() << 30 << 30)
2998 << (QStringList() << "readBack" << "unchanged")
2999 << (QVariantList() << 30 << 42);
3001 QTest::newRow("qobject module API enum values in JS")
3002 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3005 << (QStringList() << "enumValue" << "enumMethod")
3006 << (QVariantList() << 42 << 30)
3012 QTest::newRow("qobject, invalid major version fail")
3013 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3014 << QString("QDeclarativeComponent: Component is not ready")
3023 QTest::newRow("qobject, invalid minor version fail")
3024 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3025 << QString("QDeclarativeComponent: Component is not ready")
3035 void tst_qdeclarativeecmascript::moduleApi()
3037 QFETCH(QUrl, testfile);
3038 QFETCH(QString, errorMessage);
3039 QFETCH(QStringList, warningMessages);
3040 QFETCH(QStringList, readProperties);
3041 QFETCH(QVariantList, readExpectedValues);
3042 QFETCH(QStringList, writeProperties);
3043 QFETCH(QVariantList, writeValues);
3044 QFETCH(QStringList, readBackProperties);
3045 QFETCH(QVariantList, readBackExpectedValues);
3047 QDeclarativeComponent component(&engine, testfile);
3049 if (!errorMessage.isEmpty())
3050 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3052 if (warningMessages.size())
3053 foreach (const QString &warning, warningMessages)
3054 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3056 QObject *object = component.create();
3057 if (!errorMessage.isEmpty()) {
3058 QVERIFY(object == 0);
3060 QVERIFY(object != 0);
3061 for (int i = 0; i < readProperties.size(); ++i)
3062 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3063 for (int i = 0; i < writeProperties.size(); ++i)
3064 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3065 for (int i = 0; i < readBackProperties.size(); ++i)
3066 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3071 void tst_qdeclarativeecmascript::importScripts_data()
3073 QTest::addColumn<QUrl>("testfile");
3074 QTest::addColumn<QString>("errorMessage");
3075 QTest::addColumn<QStringList>("warningMessages");
3076 QTest::addColumn<QStringList>("propertyNames");
3077 QTest::addColumn<QVariantList>("propertyValues");
3079 QTest::newRow("basic functionality")
3080 << TEST_FILE("jsimport/testImport.qml")
3083 << (QStringList() << QLatin1String("importedScriptStringValue")
3084 << QLatin1String("importedScriptFunctionValue")
3085 << QLatin1String("importedModuleAttachedPropertyValue")
3086 << QLatin1String("importedModuleEnumValue"))
3087 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3092 QTest::newRow("import scoping")
3093 << TEST_FILE("jsimport/testImportScoping.qml")
3096 << (QStringList() << QLatin1String("componentError"))
3097 << (QVariantList() << QVariant(5));
3099 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3100 << TEST_FILE("jsimportfail/failOne.qml")
3102 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3103 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3104 << (QVariantList() << QVariant(QString()));
3106 QTest::newRow("javascript imports in an import should be private to the import scope")
3107 << TEST_FILE("jsimportfail/failTwo.qml")
3109 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3110 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3111 << (QVariantList() << QVariant(QString()));
3113 QTest::newRow("module imports in an import should be private to the import scope")
3114 << TEST_FILE("jsimportfail/failThree.qml")
3116 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3117 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3118 << (QVariantList() << QVariant(false));
3120 QTest::newRow("typenames in an import should be private to the import scope")
3121 << TEST_FILE("jsimportfail/failFour.qml")
3123 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3124 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3125 << (QVariantList() << QVariant(0));
3127 QTest::newRow("import with imports has it's own activation scope")
3128 << TEST_FILE("jsimportfail/failFive.qml")
3130 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3131 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3132 << (QStringList() << QLatin1String("componentError"))
3133 << (QVariantList() << QVariant(0));
3135 QTest::newRow("import pragma library script")
3136 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3139 << (QStringList() << QLatin1String("testValue"))
3140 << (QVariantList() << QVariant(31));
3142 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3143 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3146 << (QStringList() << QLatin1String("testValue"))
3147 << (QVariantList() << QVariant(0));
3149 QTest::newRow("import pragma library script which has an import")
3150 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3153 << (QStringList() << QLatin1String("testValue"))
3154 << (QVariantList() << QVariant(55));
3156 QTest::newRow("import pragma library script which has a pragma library import")
3157 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3160 << (QStringList() << QLatin1String("testValue"))
3161 << (QVariantList() << QVariant(18));
3164 void tst_qdeclarativeecmascript::importScripts()
3166 QFETCH(QUrl, testfile);
3167 QFETCH(QString, errorMessage);
3168 QFETCH(QStringList, warningMessages);
3169 QFETCH(QStringList, propertyNames);
3170 QFETCH(QVariantList, propertyValues);
3172 QDeclarativeComponent component(&engine, testfile);
3174 if (!errorMessage.isEmpty())
3175 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3177 if (warningMessages.size())
3178 foreach (const QString &warning, warningMessages)
3179 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3181 QObject *object = component.create();
3182 if (!errorMessage.isEmpty()) {
3183 QVERIFY(object == 0);
3185 QVERIFY(object != 0);
3186 for (int i = 0; i < propertyNames.size(); ++i)
3187 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3192 void tst_qdeclarativeecmascript::scarceResources()
3194 QPixmap origPixmap(100, 100);
3195 origPixmap.fill(Qt::blue);
3197 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3198 ScarceResourceObject *eo = 0;
3199 QObject *object = 0;
3201 // in the following three cases, the instance created from the component
3202 // has a property which is a copy of the scarce resource; hence, the
3203 // resource should NOT be detached prior to deletion of the object instance,
3204 // unless the resource is destroyed explicitly.
3205 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3206 object = component.create();
3207 QVERIFY(object != 0);
3208 QVERIFY(object->property("scarceResourceCopy").isValid());
3209 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3210 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3211 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3212 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3215 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3216 object = componentTwo.create();
3217 QVERIFY(object != 0);
3218 QVERIFY(object->property("scarceResourceCopy").isValid());
3219 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3220 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3221 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3222 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3225 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3226 object = componentThree.create();
3227 QVERIFY(object != 0);
3228 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3229 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3230 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3231 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3234 // in the following three cases, no other copy should exist in memory,
3235 // and so it should be detached (unless explicitly preserved).
3236 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3237 object = componentFour.create();
3238 QVERIFY(object != 0);
3239 QVERIFY(object->property("scarceResourceTest").isValid());
3240 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3241 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3242 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3243 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3246 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3247 object = componentFive.create();
3248 QVERIFY(object != 0);
3249 QVERIFY(object->property("scarceResourceTest").isValid());
3250 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3251 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3252 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3253 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3256 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3257 object = componentSix.create();
3258 QVERIFY(object != 0);
3259 QVERIFY(object->property("scarceResourceTest").isValid());
3260 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3261 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3262 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3263 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3266 // test that scarce resources are handled correctly for imports
3267 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3268 object = componentSeven.create();
3269 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3270 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3273 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3274 object = componentEight.create();
3275 QVERIFY(object != 0);
3276 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3277 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3280 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3281 object = componentNine.create();
3282 QVERIFY(object != 0);
3283 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3284 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3285 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3286 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3287 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3288 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3291 // test that scarce resources are handled properly in signal invocation
3292 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3293 object = componentTen.create();
3294 QVERIFY(object != 0);
3295 QObject *srsc = object->findChild<QObject*>("srsc");
3297 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3298 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3299 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3300 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3301 QMetaObject::invokeMethod(srsc, "testSignal");
3302 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3303 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3304 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3305 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3306 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3307 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3308 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3309 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3310 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3311 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3314 // test that scarce resources are handled properly from js functions in qml files
3315 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3316 object = componentEleven.create();
3317 QVERIFY(object != 0);
3318 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3319 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3320 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3321 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3322 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3323 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3324 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3325 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3326 QMetaObject::invokeMethod(object, "releaseScarceResource");
3327 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3328 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3329 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3330 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3333 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3334 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3335 object = componentTwelve.create();
3336 QVERIFY(object != 0);
3337 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3338 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3339 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3340 QString srp_name = object->property("srp_name").toString();
3341 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3342 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3343 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3344 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3345 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3346 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3347 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3351 void tst_qdeclarativeecmascript::propertyChangeSlots()
3353 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3354 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3355 QObject *object = component.create();
3356 QVERIFY(object != 0);
3359 // ensure that invalid property names fail properly.
3360 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3361 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3362 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3363 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3364 object = e1.create();
3365 QVERIFY(object == 0);
3368 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3369 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3370 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3371 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3372 object = e2.create();
3373 QVERIFY(object == 0);
3376 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3377 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3378 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3379 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3380 object = e3.create();
3381 QVERIFY(object == 0);
3384 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3385 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3386 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3387 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3388 object = e4.create();
3389 QVERIFY(object == 0);
3393 void tst_qdeclarativeecmascript::propertyVar_data()
3395 QTest::addColumn<QUrl>("qmlFile");
3398 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3399 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3400 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3401 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3402 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3403 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3404 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3405 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3406 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3409 void tst_qdeclarativeecmascript::propertyVar()
3411 QFETCH(QUrl, qmlFile);
3413 QDeclarativeComponent component(&engine, qmlFile);
3414 QObject *object = component.create();
3415 QVERIFY(object != 0);
3417 QCOMPARE(object->property("test").toBool(), true);
3422 // Tests that we can write QVariant values to var properties from C++
3423 void tst_qdeclarativeecmascript::propertyVarCpp()
3425 QObject *object = 0;
3427 // ensure that writing to and reading from a var property from cpp works as required.
3428 // Literal values stored in var properties can be read and written as QVariants
3429 // of a specific type, whereas object values are read as QVariantMaps.
3430 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3431 object = component.create();
3432 QVERIFY(object != 0);
3433 // assign int to property var that currently has int assigned
3434 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3435 QCOMPARE(object->property("varBound"), QVariant(15));
3436 QCOMPARE(object->property("intBound"), QVariant(15));
3437 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3438 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3439 // assign string to property var that current has bool assigned
3440 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3441 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3442 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3443 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3444 // now enforce behaviour when accessing JavaScript objects from cpp.
3445 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3449 static void gc(QDeclarativeEngine &engine)
3451 engine.collectGarbage();
3452 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3455 void tst_qdeclarativeecmascript::propertyVarOwnership()
3457 // Referenced JS objects are not collected
3459 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3460 QObject *object = component.create();
3461 QVERIFY(object != 0);
3462 QCOMPARE(object->property("test").toBool(), false);
3463 QMetaObject::invokeMethod(object, "runTest");
3464 QCOMPARE(object->property("test").toBool(), true);
3467 // Referenced JS objects are not collected
3469 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3470 QObject *object = component.create();
3471 QVERIFY(object != 0);
3472 QCOMPARE(object->property("test").toBool(), false);
3473 QMetaObject::invokeMethod(object, "runTest");
3474 QCOMPARE(object->property("test").toBool(), true);
3477 // Qt objects are not collected until they've been dereferenced
3479 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3480 QObject *object = component.create();
3481 QVERIFY(object != 0);
3483 QCOMPARE(object->property("test2").toBool(), false);
3484 QCOMPARE(object->property("test2").toBool(), false);
3486 QMetaObject::invokeMethod(object, "runTest");
3487 QCOMPARE(object->property("test1").toBool(), true);
3489 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3490 QVERIFY(!referencedObject.isNull());
3492 QVERIFY(!referencedObject.isNull());
3494 QMetaObject::invokeMethod(object, "runTest2");
3495 QCOMPARE(object->property("test2").toBool(), true);
3497 QVERIFY(referencedObject.isNull());
3501 // Self reference does not prevent Qt object collection
3503 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3504 QObject *object = component.create();
3505 QVERIFY(object != 0);
3507 QCOMPARE(object->property("test").toBool(), true);
3509 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3510 QVERIFY(!referencedObject.isNull());
3512 QVERIFY(!referencedObject.isNull());
3514 QMetaObject::invokeMethod(object, "runTest");
3516 QVERIFY(referencedObject.isNull());
3522 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3524 // The childObject has a reference to a different QObject. We want to ensure
3525 // that the different item will not be cleaned up until required. IE, the childObject
3526 // has implicit ownership of the constructed QObject.
3527 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3528 QObject *object = component.create();
3529 QVERIFY(object != 0);
3530 QMetaObject::invokeMethod(object, "assignCircular");
3531 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3532 QObject *rootObject = object->property("vp").value<QObject*>();
3533 QVERIFY(rootObject != 0);
3534 QObject *childObject = rootObject->findChild<QObject*>("text");
3535 QVERIFY(childObject != 0);
3536 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3537 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3538 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3539 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3540 QVERIFY(!qobjectGuard.isNull());
3541 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3542 QVERIFY(!qobjectGuard.isNull());
3543 QMetaObject::invokeMethod(object, "deassignCircular");
3544 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3545 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3549 void tst_qdeclarativeecmascript::propertyVarReparent()
3551 // ensure that nothing breaks if we re-parent objects
3552 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3553 QObject *object = component.create();
3554 QVERIFY(object != 0);
3555 QMetaObject::invokeMethod(object, "assignVarProp");
3556 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3557 QObject *rect = object->property("vp").value<QObject*>();
3558 QObject *text = rect->findChild<QObject*>("textOne");
3559 QObject *text2 = rect->findChild<QObject*>("textTwo");
3560 QWeakPointer<QObject> rectGuard(rect);
3561 QWeakPointer<QObject> textGuard(text);
3562 QWeakPointer<QObject> text2Guard(text2);
3563 QVERIFY(!rectGuard.isNull());
3564 QVERIFY(!textGuard.isNull());
3565 QVERIFY(!text2Guard.isNull());
3566 QCOMPARE(text->property("textCanary").toInt(), 11);
3567 QCOMPARE(text2->property("textCanary").toInt(), 12);
3568 // now construct an image which we will reparent.
3569 QMetaObject::invokeMethod(text2, "constructQObject");
3570 QObject *image = text2->property("vp").value<QObject*>();
3571 QWeakPointer<QObject> imageGuard(image);
3572 QVERIFY(!imageGuard.isNull());
3573 QCOMPARE(image->property("imageCanary").toInt(), 13);
3574 // now reparent the "Image" object (currently, it has JS ownership)
3575 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3576 QMetaObject::invokeMethod(text2, "deassignVp");
3577 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3578 QCOMPARE(text->property("textCanary").toInt(), 11);
3579 QCOMPARE(text2->property("textCanary").toInt(), 22);
3580 QVERIFY(!imageGuard.isNull()); // should still be alive.
3581 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3582 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3583 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3584 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3588 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3590 // sometimes reparenting can cause problems
3591 // (eg, if the ctxt is collected, varproperties are no longer available)
3592 // this test ensures that no crash occurs in that situation.
3593 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3594 QObject *object = component.create();
3595 QVERIFY(object != 0);
3596 QMetaObject::invokeMethod(object, "assignVarProp");
3597 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3598 QObject *rect = object->property("vp").value<QObject*>();
3599 QObject *text = rect->findChild<QObject*>("textOne");
3600 QObject *text2 = rect->findChild<QObject*>("textTwo");
3601 QWeakPointer<QObject> rectGuard(rect);
3602 QWeakPointer<QObject> textGuard(text);
3603 QWeakPointer<QObject> text2Guard(text2);
3604 QVERIFY(!rectGuard.isNull());
3605 QVERIFY(!textGuard.isNull());
3606 QVERIFY(!text2Guard.isNull());
3607 QCOMPARE(text->property("textCanary").toInt(), 11);
3608 QCOMPARE(text2->property("textCanary").toInt(), 12);
3609 // now construct an image which we will reparent.
3610 QMetaObject::invokeMethod(text2, "constructQObject");
3611 QObject *image = text2->property("vp").value<QObject*>();
3612 QWeakPointer<QObject> imageGuard(image);
3613 QVERIFY(!imageGuard.isNull());
3614 QCOMPARE(image->property("imageCanary").toInt(), 13);
3615 // now reparent the "Image" object (currently, it has JS ownership)
3616 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3617 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3618 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3619 QVERIFY(!imageGuard.isNull()); // should still be alive.
3620 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3622 QVERIFY(imageGuard.isNull()); // should now be dead.
3625 void tst_qdeclarativeecmascript::propertyVarCircular()
3627 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3628 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3629 QObject *object = component.create();
3630 QVERIFY(object != 0);
3631 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3632 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3633 QCOMPARE(object->property("canaryInt"), QVariant(5));
3634 QVariant canaryResourceVariant = object->property("canaryResource");
3635 QVERIFY(canaryResourceVariant.isValid());
3636 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3637 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3638 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3639 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3640 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3641 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3642 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3643 QCOMPARE(object->property("canaryInt"), QVariant(2));
3644 QCOMPARE(object->property("canaryResource"), QVariant(1));
3645 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3649 void tst_qdeclarativeecmascript::propertyVarCircular2()
3651 // track deletion of JS-owned parent item with Cpp-owned child
3652 // where the child has a var property referencing its parent.
3653 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3654 QObject *object = component.create();
3655 QVERIFY(object != 0);
3656 QMetaObject::invokeMethod(object, "assignCircular");
3657 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3658 QObject *rootObject = object->property("vp").value<QObject*>();
3659 QVERIFY(rootObject != 0);
3660 QObject *childObject = rootObject->findChild<QObject*>("text");
3661 QVERIFY(childObject != 0);
3662 QWeakPointer<QObject> rootObjectTracker(rootObject);
3663 QVERIFY(!rootObjectTracker.isNull());
3664 QWeakPointer<QObject> childObjectTracker(childObject);
3665 QVERIFY(!childObjectTracker.isNull());
3667 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3668 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3669 QMetaObject::invokeMethod(object, "deassignCircular");
3670 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3671 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3672 QVERIFY(childObjectTracker.isNull()); // should have been collected
3676 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3678 *(int*)(parameter) += 1;
3679 qPersistentDispose(object);
3682 void tst_qdeclarativeecmascript::propertyVarInheritance()
3684 int propertyVarWeakRefCallbackCount = 0;
3686 // enforce behaviour regarding element inheritance - ensure handle disposal.
3687 // The particular component under test here has a chain of references.
3688 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3689 QObject *object = component.create();
3690 QVERIFY(object != 0);
3691 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3692 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3693 // we want to be able to track when the varProperties array of the last metaobject is disposed
3694 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3695 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*>();
3696 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3697 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3698 v8::Persistent<v8::Value> icoCanaryHandle;
3699 v8::Persistent<v8::Value> ccoCanaryHandle;
3702 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3703 // public function which can return us a handle to something in the varProperties array.
3704 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3705 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3706 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3707 // as the varproperties array of each vmemo still references the resource.
3708 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3709 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3711 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3713 // now we deassign the var prop, which should trigger collection of item subtrees.
3714 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3715 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3716 // ensure that there are only weak handles to the underlying varProperties array remaining.
3718 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3720 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3721 // to what remains are weak, all varProperties arrays must have been collected.
3724 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3726 int propertyVarWeakRefCallbackCount = 0;
3728 // The particular component under test here does NOT have a chain of references; the
3729 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3730 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3731 QObject *object = component.create();
3732 QVERIFY(object != 0);
3733 QMetaObject::invokeMethod(object, "assignCircular");
3734 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3735 QObject *rootObject = object->property("vp").value<QObject*>();
3736 QVERIFY(rootObject != 0);
3737 QObject *childObject = rootObject->findChild<QObject*>("text");
3738 QVERIFY(childObject != 0);
3739 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3740 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3741 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3744 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3745 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3746 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3748 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3749 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3751 QMetaObject::invokeMethod(object, "deassignCircular");
3752 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3753 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3757 // Ensure that QObject type conversion works on binding assignment
3758 void tst_qdeclarativeecmascript::elementAssign()
3760 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3762 QObject *object = component.create();
3763 QVERIFY(object != 0);
3765 QCOMPARE(object->property("test").toBool(), true);
3771 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3773 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3775 QObject *object = component.create();
3776 QVERIFY(object != 0);
3778 QCOMPARE(object->property("test").toBool(), true);
3784 void tst_qdeclarativeecmascript::objectConversion()
3786 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3788 QObject *object = component.create();
3789 QVERIFY(object != 0);
3791 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3792 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3799 void tst_qdeclarativeecmascript::booleanConversion()
3801 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3803 QObject *object = component.create();
3804 QVERIFY(object != 0);
3806 QCOMPARE(object->property("test_true1").toBool(), true);
3807 QCOMPARE(object->property("test_true2").toBool(), true);
3808 QCOMPARE(object->property("test_true3").toBool(), true);
3809 QCOMPARE(object->property("test_true4").toBool(), true);
3810 QCOMPARE(object->property("test_true5").toBool(), true);
3812 QCOMPARE(object->property("test_false1").toBool(), false);
3813 QCOMPARE(object->property("test_false2").toBool(), false);
3814 QCOMPARE(object->property("test_false3").toBool(), false);
3819 void tst_qdeclarativeecmascript::handleReferenceManagement()
3824 // Linear QObject reference
3825 QDeclarativeEngine hrmEngine;
3826 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3827 QObject *object = component.create();
3828 QVERIFY(object != 0);
3829 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3830 cro->setDtorCount(&dtorCount);
3831 QMetaObject::invokeMethod(object, "createReference");
3833 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3835 hrmEngine.collectGarbage();
3836 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3837 QCOMPARE(dtorCount, 3);
3842 // Circular QObject reference
3843 QDeclarativeEngine hrmEngine;
3844 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3845 QObject *object = component.create();
3846 QVERIFY(object != 0);
3847 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3848 cro->setDtorCount(&dtorCount);
3849 QMetaObject::invokeMethod(object, "circularReference");
3851 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3853 hrmEngine.collectGarbage();
3854 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3855 QCOMPARE(dtorCount, 3);
3860 // Linear handle reference
3861 QDeclarativeEngine hrmEngine;
3862 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3863 QObject *object = component.create();
3864 QVERIFY(object != 0);
3865 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3867 crh->setDtorCount(&dtorCount);
3868 QMetaObject::invokeMethod(object, "createReference");
3869 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3870 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3871 QVERIFY(first != 0);
3872 QVERIFY(second != 0);
3873 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3874 // now we have to reparent second and make second owned by JS.
3875 second->setParent(0);
3876 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3878 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3880 hrmEngine.collectGarbage();
3881 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3882 QCOMPARE(dtorCount, 3);
3887 // Circular handle reference
3888 QDeclarativeEngine hrmEngine;
3889 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3890 QObject *object = component.create();
3891 QVERIFY(object != 0);
3892 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3894 crh->setDtorCount(&dtorCount);
3895 QMetaObject::invokeMethod(object, "circularReference");
3896 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3897 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3898 QVERIFY(first != 0);
3899 QVERIFY(second != 0);
3900 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3901 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3902 // now we have to reparent and change ownership.
3903 first->setParent(0);
3904 second->setParent(0);
3905 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3906 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3908 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3910 hrmEngine.collectGarbage();
3911 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3912 QCOMPARE(dtorCount, 3);
3917 // multiple engine interaction - linear reference
3918 QDeclarativeEngine hrmEngine1;
3919 QDeclarativeEngine hrmEngine2;
3920 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3921 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3922 QObject *object1 = component1.create();
3923 QObject *object2 = component2.create();
3924 QVERIFY(object1 != 0);
3925 QVERIFY(object2 != 0);
3926 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3927 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3930 crh1->setDtorCount(&dtorCount);
3931 crh2->setDtorCount(&dtorCount);
3932 QMetaObject::invokeMethod(object1, "createReference");
3933 QMetaObject::invokeMethod(object2, "createReference");
3934 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3935 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3936 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3937 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3938 QVERIFY(first1 != 0);
3939 QVERIFY(second1 != 0);
3940 QVERIFY(first2 != 0);
3941 QVERIFY(second2 != 0);
3942 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3943 // now we have to reparent second2 and make second2 owned by JS.
3944 second2->setParent(0);
3945 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3947 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3948 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3951 hrmEngine1.collectGarbage();
3952 hrmEngine2.collectGarbage();
3953 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3954 QCOMPARE(dtorCount, 6);
3959 // multiple engine interaction - circular reference
3960 QDeclarativeEngine hrmEngine1;
3961 QDeclarativeEngine hrmEngine2;
3962 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3963 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3964 QObject *object1 = component1.create();
3965 QObject *object2 = component2.create();
3966 QVERIFY(object1 != 0);
3967 QVERIFY(object2 != 0);
3968 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3969 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3972 crh1->setDtorCount(&dtorCount);
3973 crh2->setDtorCount(&dtorCount);
3974 QMetaObject::invokeMethod(object1, "createReference");
3975 QMetaObject::invokeMethod(object2, "createReference");
3976 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3977 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3978 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3979 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3980 QVERIFY(first1 != 0);
3981 QVERIFY(second1 != 0);
3982 QVERIFY(first2 != 0);
3983 QVERIFY(second2 != 0);
3984 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3985 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3986 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3987 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3988 // now we have to reparent and change ownership to JS.
3989 first1->setParent(0);
3990 second1->setParent(0);
3991 first2->setParent(0);
3992 second2->setParent(0);
3993 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3994 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3995 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3996 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3998 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3999 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4002 hrmEngine1.collectGarbage();
4003 hrmEngine2.collectGarbage();
4004 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4005 QCOMPARE(dtorCount, 6);
4010 // multiple engine interaction - linear reference with engine deletion
4011 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4012 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4013 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4014 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4015 QObject *object1 = component1.create();
4016 QObject *object2 = component2.create();
4017 QVERIFY(object1 != 0);
4018 QVERIFY(object2 != 0);
4019 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4020 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4023 crh1->setDtorCount(&dtorCount);
4024 crh2->setDtorCount(&dtorCount);
4025 QMetaObject::invokeMethod(object1, "createReference");
4026 QMetaObject::invokeMethod(object2, "createReference");
4027 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4028 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4029 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4030 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4031 QVERIFY(first1 != 0);
4032 QVERIFY(second1 != 0);
4033 QVERIFY(first2 != 0);
4034 QVERIFY(second2 != 0);
4035 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4036 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4037 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4038 // now we have to reparent and change ownership to JS.
4039 first1->setParent(crh1);
4040 second1->setParent(0);
4041 first2->setParent(0);
4042 second2->setParent(0);
4043 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4044 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4045 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4047 QCOMPARE(dtorCount, 0);
4050 QCOMPARE(dtorCount, 0);
4053 hrmEngine1->collectGarbage();
4054 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4055 QCOMPARE(dtorCount, 6);
4060 void tst_qdeclarativeecmascript::stringArg()
4062 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4063 QObject *object = component.create();
4064 QVERIFY(object != 0);
4065 QMetaObject::invokeMethod(object, "success");
4066 QVERIFY(object->property("returnValue").toBool());
4068 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4069 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4070 QMetaObject::invokeMethod(object, "failure");
4071 QVERIFY(object->property("returnValue").toBool());
4076 void tst_qdeclarativeecmascript::readonlyDeclaration()
4078 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4080 QObject *object = component.create();
4081 QVERIFY(object != 0);
4083 QCOMPARE(object->property("test").toBool(), true);
4088 Q_DECLARE_METATYPE(QList<int>)
4089 Q_DECLARE_METATYPE(QList<qreal>)
4090 Q_DECLARE_METATYPE(QList<bool>)
4091 Q_DECLARE_METATYPE(QList<QString>)
4092 Q_DECLARE_METATYPE(QList<QUrl>)
4093 void tst_qdeclarativeecmascript::sequenceConversionRead()
4096 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4097 QDeclarativeComponent component(&engine, qmlFile);
4098 QObject *object = component.create();
4099 QVERIFY(object != 0);
4100 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4103 QMetaObject::invokeMethod(object, "readSequences");
4104 QList<int> intList; intList << 1 << 2 << 3 << 4;
4105 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4106 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4107 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4108 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4109 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4110 QList<bool> boolList; boolList << true << false << true << false;
4111 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4112 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4113 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4114 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4115 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4116 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4117 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4118 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4119 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4120 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4121 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4123 QMetaObject::invokeMethod(object, "readSequenceElements");
4124 QCOMPARE(object->property("intVal").toInt(), 2);
4125 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4126 QCOMPARE(object->property("boolVal").toBool(), false);
4127 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4128 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4129 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4131 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4132 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4134 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4135 QDeclarativeProperty seqProp(seq, "intListProperty");
4136 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4137 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4138 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4140 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4141 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4147 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4148 QDeclarativeComponent component(&engine, qmlFile);
4149 QObject *object = component.create();
4150 QVERIFY(object != 0);
4151 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4154 // we haven't registered QList<QPoint> as a sequence type.
4155 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4156 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4157 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4158 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4160 QMetaObject::invokeMethod(object, "performTest");
4162 // QList<QPoint> has not been registered as a sequence type.
4163 QCOMPARE(object->property("pointListLength").toInt(), 0);
4164 QVERIFY(!object->property("pointList").isValid());
4165 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4166 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4167 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4173 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4176 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4177 QDeclarativeComponent component(&engine, qmlFile);
4178 QObject *object = component.create();
4179 QVERIFY(object != 0);
4180 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4183 QMetaObject::invokeMethod(object, "writeSequences");
4184 QCOMPARE(object->property("success").toBool(), true);
4186 QMetaObject::invokeMethod(object, "writeSequenceElements");
4187 QCOMPARE(object->property("success").toBool(), true);
4189 QMetaObject::invokeMethod(object, "writeOtherElements");
4190 QCOMPARE(object->property("success").toBool(), true);
4192 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4193 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4199 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4200 QDeclarativeComponent component(&engine, qmlFile);
4201 QObject *object = component.create();
4202 QVERIFY(object != 0);
4203 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4206 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4207 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4208 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4210 QMetaObject::invokeMethod(object, "performTest");
4212 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4213 QCOMPARE(seq->pointListProperty(), pointList);
4219 void tst_qdeclarativeecmascript::sequenceConversionArray()
4221 // ensure that in JS the returned sequences act just like normal JS Arrays.
4222 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4223 QDeclarativeComponent component(&engine, qmlFile);
4224 QObject *object = component.create();
4225 QVERIFY(object != 0);
4226 //QMetaObject::invokeMethod(object, "indexedAccess");
4227 //QVERIFY(object->property("success").toBool());
4228 //QMetaObject::invokeMethod(object, "arrayOperations");
4229 //QVERIFY(object->property("success").toBool());
4230 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4231 QVERIFY(object->property("success").toBool());
4232 //QMetaObject::invokeMethod(object, "testReferenceDeletion");
4233 //QCOMPARE(object->property("referenceDeletion").toBool(), true);
4237 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4239 // ensure that sequence conversion operations work correctly in a worker thread
4240 // and that serialisation between the main and worker thread succeeds.
4241 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4242 QDeclarativeComponent component(&engine, qmlFile);
4243 QObject *object = component.create();
4244 QVERIFY(object != 0);
4246 QMetaObject::invokeMethod(object, "testIntSequence");
4247 QTRY_VERIFY(object->property("finished").toBool());
4248 QVERIFY(object->property("success").toBool());
4250 QMetaObject::invokeMethod(object, "testQrealSequence");
4251 QTRY_VERIFY(object->property("finished").toBool());
4252 QVERIFY(object->property("success").toBool());
4254 QMetaObject::invokeMethod(object, "testBoolSequence");
4255 QTRY_VERIFY(object->property("finished").toBool());
4256 QVERIFY(object->property("success").toBool());
4258 QMetaObject::invokeMethod(object, "testStringSequence");
4259 QTRY_VERIFY(object->property("finished").toBool());
4260 QVERIFY(object->property("success").toBool());
4262 QMetaObject::invokeMethod(object, "testQStringSequence");
4263 QTRY_VERIFY(object->property("finished").toBool());
4264 QVERIFY(object->property("success").toBool());
4266 QMetaObject::invokeMethod(object, "testUrlSequence");
4267 QTRY_VERIFY(object->property("finished").toBool());
4268 QVERIFY(object->property("success").toBool());
4270 QMetaObject::invokeMethod(object, "testVariantSequence");
4271 QTRY_VERIFY(object->property("finished").toBool());
4272 QVERIFY(object->property("success").toBool());
4277 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4280 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4281 QDeclarativeComponent component(&engine, qmlFile);
4282 QObject *object = component.create();
4283 QVERIFY(object != 0);
4284 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4285 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4286 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4287 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4288 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4293 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4294 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4295 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4296 QDeclarativeComponent component(&engine, qmlFile);
4297 QObject *object = component.create();
4298 QVERIFY(object != 0);
4303 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4305 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4306 QDeclarativeComponent component(&engine, qmlFile);
4307 QObject *object = component.create();
4308 QVERIFY(object != 0);
4309 QMetaObject::invokeMethod(object, "testCopySequences");
4310 QCOMPARE(object->property("success").toBool(), true);
4311 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4312 QCOMPARE(object->property("success").toBool(), true);
4313 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4314 QCOMPARE(object->property("success").toBool(), true);
4318 // Test that assigning a null object works
4319 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4320 void tst_qdeclarativeecmascript::nullObjectBinding()
4322 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4324 QObject *object = component.create();
4325 QVERIFY(object != 0);
4327 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4332 // Test that bindings don't evaluate once the engine has been destroyed
4333 void tst_qdeclarativeecmascript::deletedEngine()
4335 QDeclarativeEngine *engine = new QDeclarativeEngine;
4336 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4338 QObject *object = component.create();
4339 QVERIFY(object != 0);
4341 QCOMPARE(object->property("a").toInt(), 39);
4342 object->setProperty("b", QVariant(9));
4343 QCOMPARE(object->property("a").toInt(), 117);
4347 QCOMPARE(object->property("a").toInt(), 117);
4348 object->setProperty("b", QVariant(10));
4349 QCOMPARE(object->property("a").toInt(), 117);
4354 // Test the crashing part of QTBUG-9705
4355 void tst_qdeclarativeecmascript::libraryScriptAssert()
4357 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4359 QObject *object = component.create();
4360 QVERIFY(object != 0);
4365 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4367 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4369 QObject *object = component.create();
4370 QVERIFY(object != 0);
4372 QCOMPARE(object->property("test1").toInt(), 10);
4373 QCOMPARE(object->property("test2").toInt(), 11);
4375 object->setProperty("runTest", true);
4377 QCOMPARE(object->property("test1"), QVariant());
4378 QCOMPARE(object->property("test2"), QVariant());
4384 void tst_qdeclarativeecmascript::qtbug_9792()
4386 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4388 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4390 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4391 QVERIFY(object != 0);
4393 QString message = QString(QLatin1String("Hello world! (%1:%2)")).arg(TEST_FILE("qtbug_9792.qml").toString()).arg(4);
4394 QTest::ignoreMessage(QtDebugMsg, qPrintable(message));
4395 object->basicSignal();
4399 transientErrorsMsgCount = 0;
4400 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4402 object->basicSignal();
4404 qInstallMsgHandler(old);
4406 QCOMPARE(transientErrorsMsgCount, 0);
4411 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4412 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4414 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4416 QObject *o = component.create();
4419 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4420 QVERIFY(nested != 0);
4422 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4425 nested = qvariant_cast<QObject *>(o->property("object"));
4426 QVERIFY(nested == 0);
4428 // If the bug is present, the next line will crash
4432 // Test that we shut down without stupid warnings
4433 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4436 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4438 QObject *o = component.create();
4440 transientErrorsMsgCount = 0;
4441 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4445 qInstallMsgHandler(old);
4447 QCOMPARE(transientErrorsMsgCount, 0);
4452 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4454 QObject *o = component.create();
4456 transientErrorsMsgCount = 0;
4457 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4461 qInstallMsgHandler(old);
4463 QCOMPARE(transientErrorsMsgCount, 0);
4467 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4470 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4472 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4475 QVERIFY(o->objectProperty() != 0);
4477 o->setProperty("runTest", true);
4479 QVERIFY(o->objectProperty() == 0);
4485 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4487 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4490 QVERIFY(o->objectProperty() == 0);
4496 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4498 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4500 QString url = component.url().toString();
4501 QString warning = url + ":4: Unable to assign a function to a property.";
4502 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4504 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4507 QVERIFY(!o->property("a").isValid());
4512 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4514 QFETCH(QString, triggerProperty);
4516 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4517 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4519 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4521 QVERIFY(!o->property("a").isValid());
4523 o->setProperty("aNumber", QVariant(5));
4524 o->setProperty(triggerProperty.toUtf8().constData(), true);
4525 QCOMPARE(o->property("a"), QVariant(50));
4527 o->setProperty("aNumber", QVariant(10));
4528 QCOMPARE(o->property("a"), QVariant(100));
4533 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4535 QTest::addColumn<QString>("triggerProperty");
4537 QTest::newRow("assign to property") << "assignToProperty";
4538 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4540 QTest::newRow("assign to value type") << "assignToValueType";
4542 QTest::newRow("use 'this'") << "assignWithThis";
4543 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4546 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4548 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4549 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4551 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4553 QVERIFY(!o->property("a").isValid());
4555 o->setProperty("assignFuncWithoutReturn", true);
4556 QVERIFY(!o->property("a").isValid());
4558 QString url = component.url().toString();
4559 QString warning = url + ":67: Unable to assign QString to int";
4560 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4561 o->setProperty("assignWrongType", true);
4563 warning = url + ":71: Unable to assign QString to int";
4564 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4565 o->setProperty("assignWrongTypeToValueType", true);
4570 void tst_qdeclarativeecmascript::eval()
4572 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4574 QObject *o = component.create();
4577 QCOMPARE(o->property("test1").toBool(), true);
4578 QCOMPARE(o->property("test2").toBool(), true);
4579 QCOMPARE(o->property("test3").toBool(), true);
4580 QCOMPARE(o->property("test4").toBool(), true);
4581 QCOMPARE(o->property("test5").toBool(), true);
4586 void tst_qdeclarativeecmascript::function()
4588 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4590 QObject *o = component.create();
4593 QCOMPARE(o->property("test1").toBool(), true);
4594 QCOMPARE(o->property("test2").toBool(), true);
4595 QCOMPARE(o->property("test3").toBool(), true);
4600 // Test the "Qt.include" method
4601 void tst_qdeclarativeecmascript::include()
4603 // Non-library relative include
4605 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4606 QObject *o = component.create();
4609 QCOMPARE(o->property("test0").toInt(), 99);
4610 QCOMPARE(o->property("test1").toBool(), true);
4611 QCOMPARE(o->property("test2").toBool(), true);
4612 QCOMPARE(o->property("test2_1").toBool(), true);
4613 QCOMPARE(o->property("test3").toBool(), true);
4614 QCOMPARE(o->property("test3_1").toBool(), true);
4619 // Library relative include
4621 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4622 QObject *o = component.create();
4625 QCOMPARE(o->property("test0").toInt(), 99);
4626 QCOMPARE(o->property("test1").toBool(), true);
4627 QCOMPARE(o->property("test2").toBool(), true);
4628 QCOMPARE(o->property("test2_1").toBool(), true);
4629 QCOMPARE(o->property("test3").toBool(), true);
4630 QCOMPARE(o->property("test3_1").toBool(), true);
4637 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4638 QObject *o = component.create();
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);
4646 QCOMPARE(o->property("test6").toBool(), true);
4651 // Including file with ".pragma library"
4653 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4654 QObject *o = component.create();
4656 QCOMPARE(o->property("test1").toInt(), 100);
4663 TestHTTPServer server(8111);
4664 QVERIFY(server.isValid());
4665 server.serveDirectory(TESTDATA(""));
4667 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4668 QObject *o = component.create();
4671 QTRY_VERIFY(o->property("done").toBool() == true);
4672 QTRY_VERIFY(o->property("done2").toBool() == true);
4674 QCOMPARE(o->property("test1").toBool(), true);
4675 QCOMPARE(o->property("test2").toBool(), true);
4676 QCOMPARE(o->property("test3").toBool(), true);
4677 QCOMPARE(o->property("test4").toBool(), true);
4678 QCOMPARE(o->property("test5").toBool(), true);
4680 QCOMPARE(o->property("test6").toBool(), true);
4681 QCOMPARE(o->property("test7").toBool(), true);
4682 QCOMPARE(o->property("test8").toBool(), true);
4683 QCOMPARE(o->property("test9").toBool(), true);
4684 QCOMPARE(o->property("test10").toBool(), true);
4691 TestHTTPServer server(8111);
4692 QVERIFY(server.isValid());
4693 server.serveDirectory(TESTDATA(""));
4695 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4696 QObject *o = component.create();
4699 QTRY_VERIFY(o->property("done").toBool() == true);
4701 QCOMPARE(o->property("test1").toBool(), true);
4702 QCOMPARE(o->property("test2").toBool(), true);
4703 QCOMPARE(o->property("test3").toBool(), true);
4709 void tst_qdeclarativeecmascript::signalHandlers()
4711 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4712 QObject *o = component.create();
4715 QVERIFY(o->property("count").toInt() == 0);
4716 QMetaObject::invokeMethod(o, "testSignalCall");
4717 QCOMPARE(o->property("count").toInt(), 1);
4719 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4720 QCOMPARE(o->property("count").toInt(), 1);
4721 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4723 QVERIFY(o->property("funcCount").toInt() == 0);
4724 QMetaObject::invokeMethod(o, "testSignalConnection");
4725 QCOMPARE(o->property("funcCount").toInt(), 1);
4727 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4728 QCOMPARE(o->property("funcCount").toInt(), 2);
4730 QMetaObject::invokeMethod(o, "testSignalDefined");
4731 QCOMPARE(o->property("definedResult").toBool(), true);
4733 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4734 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4739 void tst_qdeclarativeecmascript::qtbug_10696()
4741 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4742 QObject *o = component.create();
4747 void tst_qdeclarativeecmascript::qtbug_11606()
4749 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4750 QObject *o = component.create();
4752 QCOMPARE(o->property("test").toBool(), true);
4756 void tst_qdeclarativeecmascript::qtbug_11600()
4758 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4759 QObject *o = component.create();
4761 QCOMPARE(o->property("test").toBool(), true);
4765 // Reading and writing non-scriptable properties should fail
4766 void tst_qdeclarativeecmascript::nonscriptable()
4768 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4769 QObject *o = component.create();
4771 QCOMPARE(o->property("readOk").toBool(), true);
4772 QCOMPARE(o->property("writeOk").toBool(), true);
4776 // deleteLater() should not be callable from QML
4777 void tst_qdeclarativeecmascript::deleteLater()
4779 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4780 QObject *o = component.create();
4782 QCOMPARE(o->property("test").toBool(), true);
4786 void tst_qdeclarativeecmascript::in()
4788 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4789 QObject *o = component.create();
4791 QCOMPARE(o->property("test1").toBool(), true);
4792 QCOMPARE(o->property("test2").toBool(), true);
4796 void tst_qdeclarativeecmascript::typeOf()
4798 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4799 QObject *o = component.create();
4801 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4802 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4803 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4804 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4805 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4806 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4807 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4808 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4809 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4810 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4815 void tst_qdeclarativeecmascript::sharedAttachedObject()
4817 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4818 QObject *o = component.create();
4820 QCOMPARE(o->property("test1").toBool(), true);
4821 QCOMPARE(o->property("test2").toBool(), true);
4826 void tst_qdeclarativeecmascript::objectName()
4828 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4829 QObject *o = component.create();
4832 QCOMPARE(o->property("test1").toString(), QString("hello"));
4833 QCOMPARE(o->property("test2").toString(), QString("ell"));
4835 o->setObjectName("world");
4837 QCOMPARE(o->property("test1").toString(), QString("world"));
4838 QCOMPARE(o->property("test2").toString(), QString("orl"));
4843 void tst_qdeclarativeecmascript::writeRemovesBinding()
4845 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4846 QObject *o = component.create();
4849 QCOMPARE(o->property("test").toBool(), true);
4854 // Test bindings assigned to alias properties actually assign to the alias' target
4855 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4857 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4858 QObject *o = component.create();
4861 QCOMPARE(o->property("test").toBool(), true);
4866 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4867 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4870 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4871 QObject *o = component.create();
4874 QCOMPARE(o->property("test").toBool(), true);
4880 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4881 QObject *o = component.create();
4884 QCOMPARE(o->property("test").toBool(), true);
4890 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4891 QObject *o = component.create();
4894 QCOMPARE(o->property("test").toBool(), true);
4900 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4901 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4904 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4905 QObject *o = component.create();
4908 QCOMPARE(o->property("test").toBool(), true);
4914 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4915 QObject *o = component.create();
4918 QCOMPARE(o->property("test").toBool(), true);
4924 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4925 QObject *o = component.create();
4928 QCOMPARE(o->property("test").toBool(), true);
4934 // Allow an alais to a composite element
4936 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4938 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4940 QObject *object = component.create();
4941 QVERIFY(object != 0);
4946 void tst_qdeclarativeecmascript::qtbug_20344()
4948 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
4950 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
4951 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
4953 QObject *object = component.create();
4954 QVERIFY(object != 0);
4959 void tst_qdeclarativeecmascript::revisionErrors()
4962 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4963 QString url = component.url().toString();
4965 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4966 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4967 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4969 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4970 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4971 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4972 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4973 QVERIFY(object != 0);
4977 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4978 QString url = component.url().toString();
4980 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4981 // method2, prop2 from MyRevisionedClass not available
4982 // method4, prop4 from MyRevisionedSubclass not available
4983 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4984 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4985 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4986 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4987 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4989 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4990 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4991 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4992 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4993 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4994 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4995 QVERIFY(object != 0);
4999 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5000 QString url = component.url().toString();
5002 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5003 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5004 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5005 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5006 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5007 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5008 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5009 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5010 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5011 QVERIFY(object != 0);
5016 void tst_qdeclarativeecmascript::revision()
5019 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5020 QString url = component.url().toString();
5022 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5023 QVERIFY(object != 0);
5027 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5028 QString url = component.url().toString();
5030 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5031 QVERIFY(object != 0);
5035 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5036 QString url = component.url().toString();
5038 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5039 QVERIFY(object != 0);
5042 // Test that non-root classes can resolve revisioned methods
5044 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5046 QObject *object = component.create();
5047 QVERIFY(object != 0);
5048 QCOMPARE(object->property("test").toReal(), 11.);
5053 void tst_qdeclarativeecmascript::realToInt()
5055 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5056 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5057 QVERIFY(object != 0);
5059 QMetaObject::invokeMethod(object, "test1");
5060 QCOMPARE(object->value(), int(4));
5061 QMetaObject::invokeMethod(object, "test2");
5062 QCOMPARE(object->value(), int(8));
5064 void tst_qdeclarativeecmascript::dynamicString()
5066 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5067 QObject *object = component.create();
5068 QVERIFY(object != 0);
5069 QCOMPARE(object->property("stringProperty").toString(),
5070 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5073 void tst_qdeclarativeecmascript::automaticSemicolon()
5075 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5076 QObject *object = component.create();
5077 QVERIFY(object != 0);
5080 void tst_qdeclarativeecmascript::unaryExpression()
5082 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5083 QObject *object = component.create();
5084 QVERIFY(object != 0);
5087 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5088 void tst_qdeclarativeecmascript::doubleEvaluate()
5090 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5091 QObject *object = component.create();
5092 QVERIFY(object != 0);
5093 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5095 QCOMPARE(wc->count(), 1);
5097 wc->setProperty("x", 9);
5099 QCOMPARE(wc->count(), 2);
5104 static QStringList messages;
5105 static void captureMsgHandler(QtMsgType, const char *msg)
5107 messages.append(QLatin1String(msg));
5110 void tst_qdeclarativeecmascript::nonNotifyable()
5112 QV4Compiler::enableV4(false);
5113 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5114 QV4Compiler::enableV4(true);
5116 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5118 QObject *object = component.create();
5119 qInstallMsgHandler(old);
5121 QVERIFY(object != 0);
5123 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5124 component.url().toString() +
5125 QLatin1String(":5 depends on non-NOTIFYable properties:");
5126 QString expected2 = QLatin1String(" ") +
5127 QLatin1String(object->metaObject()->className()) +
5128 QLatin1String("::value");
5130 QCOMPARE(messages.length(), 2);
5131 QCOMPARE(messages.at(0), expected1);
5132 QCOMPARE(messages.at(1), expected2);
5137 void tst_qdeclarativeecmascript::forInLoop()
5139 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5140 QObject *object = component.create();
5141 QVERIFY(object != 0);
5143 QMetaObject::invokeMethod(object, "listProperty");
5145 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5146 QCOMPARE(r.size(), 3);
5147 QCOMPARE(r[0],QLatin1String("0=obj1"));
5148 QCOMPARE(r[1],QLatin1String("1=obj2"));
5149 QCOMPARE(r[2],QLatin1String("2=obj3"));
5151 //TODO: should test for in loop for other objects (such as QObjects) as well.
5156 // An object the binding depends on is deleted while the binding is still running
5157 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5159 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5160 QObject *object = component.create();
5161 QVERIFY(object != 0);
5165 void tst_qdeclarativeecmascript::qtbug_22679()
5168 object.setStringProperty(QLatin1String("Please work correctly"));
5169 engine.rootContext()->setContextProperty("contextProp", &object);
5171 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5172 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5173 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5175 QObject *o = component.create();
5177 QCOMPARE(warningsSpy.count(), 0);
5181 QTEST_MAIN(tst_qdeclarativeecmascript)
5183 #include "tst_qdeclarativeecmascript.moc"