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 "testtypes.h"
55 #include "testhttpserver.h"
56 #include "../shared/util.h"
59 This test covers evaluation of ECMAScript expressions and bindings from within
60 QML. This does not include static QML language issues.
62 Static QML language issues are covered in qmllanguage
64 inline QUrl TEST_FILE(const QString &filename)
66 return QUrl::fromLocalFile(TESTDATA(filename));
69 inline QUrl TEST_FILE(const char *filename)
71 return TEST_FILE(QLatin1String(filename));
74 class tst_qdeclarativeecmascript : public QObject
78 tst_qdeclarativeecmascript() {}
82 void assignBasicTypes();
83 void idShortcutInvalidates();
84 void boolPropertiesEvaluateAsBool();
86 void signalAssignment();
88 void basicExpressions();
89 void basicExpressions_data();
90 void arrayExpressions();
91 void contextPropertiesTriggerReeval();
92 void objectPropertiesTriggerReeval();
93 void deferredProperties();
94 void deferredPropertiesErrors();
95 void extensionObjects();
96 void overrideExtensionProperties();
97 void attachedProperties();
99 void valueTypeFunctions();
100 void constantsOverrideBindings();
101 void outerBindingOverridesInnerBinding();
102 void aliasPropertyAndBinding();
103 void aliasPropertyReset();
104 void nonExistentAttachedObject();
107 void signalParameterTypes();
108 void objectsCompareAsEqual();
109 void dynamicCreation_data();
110 void dynamicCreation();
111 void dynamicDestruction();
112 void objectToString();
113 void objectHasOwnProperty();
114 void selfDeletingBinding();
115 void extendedObjectPropertyLookup();
117 void functionErrors();
118 void propertyAssignmentErrors();
119 void signalTriggeredBindings();
120 void listProperties();
121 void exceptionClearsOnReeval();
122 void exceptionSlotProducesWarning();
123 void exceptionBindingProducesWarning();
124 void transientErrors();
125 void shutdownErrors();
126 void compositePropertyType();
128 void undefinedResetsProperty();
129 void listToVariant();
130 void listAssignment();
131 void multiEngineObject();
132 void deletedObject();
133 void attachedPropertyScope();
134 void scriptConnect();
135 void scriptDisconnect();
137 void cppOwnershipReturnValue();
138 void ownershipCustomReturnValue();
139 void qlistqobjectMethods();
140 void strictlyEquals();
142 void numberAssignment();
143 void propertySplicing();
144 void signalWithUnknownTypes();
145 void signalWithJSValueInVariant_data();
146 void signalWithJSValueInVariant();
147 void signalWithJSValueInVariant_twoEngines_data();
148 void signalWithJSValueInVariant_twoEngines();
149 void moduleApi_data();
151 void importScripts_data();
152 void importScripts();
153 void scarceResources();
154 void propertyChangeSlots();
155 void propertyVar_data();
157 void propertyVarCpp();
158 void propertyVarOwnership();
159 void propertyVarImplicitOwnership();
160 void propertyVarReparent();
161 void propertyVarReparentNullContext();
162 void propertyVarCircular();
163 void propertyVarCircular2();
164 void propertyVarInheritance();
165 void propertyVarInheritance2();
166 void elementAssign();
167 void objectPassThroughSignals();
168 void objectConversion();
169 void booleanConversion();
170 void handleReferenceManagement();
172 void readonlyDeclaration();
173 void sequenceConversionRead();
174 void sequenceConversionWrite();
175 void sequenceConversionArray();
176 void sequenceConversionThreads();
177 void sequenceConversionBindings();
178 void sequenceConversionCopy();
182 void dynamicCreationCrash();
183 void dynamicCreationOwnership();
185 void nullObjectBinding();
186 void deletedEngine();
187 void libraryScriptAssert();
188 void variantsAssignedUndefined();
190 void qtcreatorbug_1289();
191 void noSpuriousWarningsAtShutdown();
192 void canAssignNullToQObject();
193 void functionAssignment_fromBinding();
194 void functionAssignment_fromJS();
195 void functionAssignment_fromJS_data();
196 void functionAssignmentfromJS_invalid();
202 void nonscriptable();
206 void sharedAttachedObject();
208 void writeRemovesBinding();
209 void aliasBindingsAssignCorrectly();
210 void aliasBindingsOverrideTarget();
211 void aliasWritesOverrideBindings();
212 void aliasToCompositeElement();
214 void dynamicString();
216 void signalHandlers();
217 void doubleEvaluate();
220 void callQtInvokables();
221 void invokableObjectArg();
222 void invokableObjectRet();
224 void revisionErrors();
227 void automaticSemicolon();
230 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
231 QDeclarativeEngine engine;
234 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
236 void tst_qdeclarativeecmascript::assignBasicTypes()
239 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
240 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
241 QVERIFY(object != 0);
242 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
243 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
244 QCOMPARE(object->stringProperty(), QString("Hello World!"));
245 QCOMPARE(object->uintProperty(), uint(10));
246 QCOMPARE(object->intProperty(), -19);
247 QCOMPARE((float)object->realProperty(), float(23.2));
248 QCOMPARE((float)object->doubleProperty(), float(-19.75));
249 QCOMPARE((float)object->floatProperty(), float(8.5));
250 QCOMPARE(object->colorProperty(), QColor("red"));
251 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
252 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
253 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
254 QCOMPARE(object->pointProperty(), QPoint(99,13));
255 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
256 QCOMPARE(object->sizeProperty(), QSize(99, 13));
257 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
258 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
259 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
260 QCOMPARE(object->boolProperty(), true);
261 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
262 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
263 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
267 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
268 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
269 QVERIFY(object != 0);
270 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
271 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
272 QCOMPARE(object->stringProperty(), QString("Hello World!"));
273 QCOMPARE(object->uintProperty(), uint(10));
274 QCOMPARE(object->intProperty(), -19);
275 QCOMPARE((float)object->realProperty(), float(23.2));
276 QCOMPARE((float)object->doubleProperty(), float(-19.75));
277 QCOMPARE((float)object->floatProperty(), float(8.5));
278 QCOMPARE(object->colorProperty(), QColor("red"));
279 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
280 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
281 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
282 QCOMPARE(object->pointProperty(), QPoint(99,13));
283 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
284 QCOMPARE(object->sizeProperty(), QSize(99, 13));
285 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
286 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
287 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
288 QCOMPARE(object->boolProperty(), true);
289 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
290 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
291 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
296 void tst_qdeclarativeecmascript::idShortcutInvalidates()
299 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
300 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
301 QVERIFY(object != 0);
302 QVERIFY(object->objectProperty() != 0);
303 delete object->objectProperty();
304 QVERIFY(object->objectProperty() == 0);
309 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
310 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
311 QVERIFY(object != 0);
312 QVERIFY(object->objectProperty() != 0);
313 delete object->objectProperty();
314 QVERIFY(object->objectProperty() == 0);
319 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
322 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
323 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
324 QVERIFY(object != 0);
325 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
329 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
330 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
331 QVERIFY(object != 0);
332 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
337 void tst_qdeclarativeecmascript::signalAssignment()
340 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
341 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
342 QVERIFY(object != 0);
343 QCOMPARE(object->string(), QString());
344 emit object->basicSignal();
345 QCOMPARE(object->string(), QString("pass"));
350 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
351 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
352 QVERIFY(object != 0);
353 QCOMPARE(object->string(), QString());
354 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
355 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
360 void tst_qdeclarativeecmascript::methods()
363 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
364 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
365 QVERIFY(object != 0);
366 QCOMPARE(object->methodCalled(), false);
367 QCOMPARE(object->methodIntCalled(), false);
368 emit object->basicSignal();
369 QCOMPARE(object->methodCalled(), true);
370 QCOMPARE(object->methodIntCalled(), false);
375 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
376 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
377 QVERIFY(object != 0);
378 QCOMPARE(object->methodCalled(), false);
379 QCOMPARE(object->methodIntCalled(), false);
380 emit object->basicSignal();
381 QCOMPARE(object->methodCalled(), false);
382 QCOMPARE(object->methodIntCalled(), true);
387 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
388 QObject *object = component.create();
389 QVERIFY(object != 0);
390 QCOMPARE(object->property("test").toInt(), 19);
395 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
396 QObject *object = component.create();
397 QVERIFY(object != 0);
398 QCOMPARE(object->property("test").toInt(), 19);
399 QCOMPARE(object->property("test2").toInt(), 17);
400 QCOMPARE(object->property("test3").toInt(), 16);
405 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
406 QObject *object = component.create();
407 QVERIFY(object != 0);
408 QCOMPARE(object->property("test").toInt(), 9);
413 void tst_qdeclarativeecmascript::bindingLoop()
415 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
416 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
417 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
418 QObject *object = component.create();
419 QVERIFY(object != 0);
423 void tst_qdeclarativeecmascript::basicExpressions_data()
425 QTest::addColumn<QString>("expression");
426 QTest::addColumn<QVariant>("result");
427 QTest::addColumn<bool>("nest");
429 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
430 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
431 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
432 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
433 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
434 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
435 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
436 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
437 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
438 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
439 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
440 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
441 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
442 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
443 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
444 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
445 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
446 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
447 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
450 void tst_qdeclarativeecmascript::basicExpressions()
452 QFETCH(QString, expression);
453 QFETCH(QVariant, result);
459 MyDefaultObject1 default1;
460 MyDefaultObject3 default3;
461 object1.setStringProperty("Object1");
462 object2.setStringProperty("Object2");
463 object3.setStringProperty("Object3");
465 QDeclarativeContext context(engine.rootContext());
466 QDeclarativeContext nestedContext(&context);
468 context.setContextObject(&default1);
469 context.setContextProperty("a", QVariant(1944));
470 context.setContextProperty("b", QVariant("Milk"));
471 context.setContextProperty("object", &object1);
472 context.setContextProperty("objectOverride", &object2);
473 nestedContext.setContextObject(&default3);
474 nestedContext.setContextProperty("b", QVariant("Cow"));
475 nestedContext.setContextProperty("objectOverride", &object3);
476 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
478 MyExpression expr(nest?&nestedContext:&context, expression);
479 QCOMPARE(expr.evaluate(), result);
482 void tst_qdeclarativeecmascript::arrayExpressions()
488 QDeclarativeContext context(engine.rootContext());
489 context.setContextProperty("a", &obj1);
490 context.setContextProperty("b", &obj2);
491 context.setContextProperty("c", &obj3);
493 MyExpression expr(&context, "[a, b, c, 10]");
494 QVariant result = expr.evaluate();
495 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
496 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
497 QCOMPARE(list.count(), 4);
498 QCOMPARE(list.at(0), &obj1);
499 QCOMPARE(list.at(1), &obj2);
500 QCOMPARE(list.at(2), &obj3);
501 QCOMPARE(list.at(3), (QObject *)0);
504 // Tests that modifying a context property will reevaluate expressions
505 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
507 QDeclarativeContext context(engine.rootContext());
510 MyQmlObject *object3 = new MyQmlObject;
512 object1.setStringProperty("Hello");
513 object2.setStringProperty("World");
515 context.setContextProperty("testProp", QVariant(1));
516 context.setContextProperty("testObj", &object1);
517 context.setContextProperty("testObj2", object3);
520 MyExpression expr(&context, "testProp + 1");
521 QCOMPARE(expr.changed, false);
522 QCOMPARE(expr.evaluate(), QVariant(2));
524 context.setContextProperty("testProp", QVariant(2));
525 QCOMPARE(expr.changed, true);
526 QCOMPARE(expr.evaluate(), QVariant(3));
530 MyExpression expr(&context, "testProp + testProp + testProp");
531 QCOMPARE(expr.changed, false);
532 QCOMPARE(expr.evaluate(), QVariant(6));
534 context.setContextProperty("testProp", QVariant(4));
535 QCOMPARE(expr.changed, true);
536 QCOMPARE(expr.evaluate(), QVariant(12));
540 MyExpression expr(&context, "testObj.stringProperty");
541 QCOMPARE(expr.changed, false);
542 QCOMPARE(expr.evaluate(), QVariant("Hello"));
544 context.setContextProperty("testObj", &object2);
545 QCOMPARE(expr.changed, true);
546 QCOMPARE(expr.evaluate(), QVariant("World"));
550 MyExpression expr(&context, "testObj.stringProperty /**/");
551 QCOMPARE(expr.changed, false);
552 QCOMPARE(expr.evaluate(), QVariant("World"));
554 context.setContextProperty("testObj", &object1);
555 QCOMPARE(expr.changed, true);
556 QCOMPARE(expr.evaluate(), QVariant("Hello"));
560 MyExpression expr(&context, "testObj2");
561 QCOMPARE(expr.changed, false);
562 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
568 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
570 QDeclarativeContext context(engine.rootContext());
574 context.setContextProperty("testObj", &object1);
576 object1.setStringProperty(QLatin1String("Hello"));
577 object2.setStringProperty(QLatin1String("Dog"));
578 object3.setStringProperty(QLatin1String("Cat"));
581 MyExpression expr(&context, "testObj.stringProperty");
582 QCOMPARE(expr.changed, false);
583 QCOMPARE(expr.evaluate(), QVariant("Hello"));
585 object1.setStringProperty(QLatin1String("World"));
586 QCOMPARE(expr.changed, true);
587 QCOMPARE(expr.evaluate(), QVariant("World"));
591 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
592 QCOMPARE(expr.changed, false);
593 QCOMPARE(expr.evaluate(), QVariant());
595 object1.setObjectProperty(&object2);
596 QCOMPARE(expr.changed, true);
597 expr.changed = false;
598 QCOMPARE(expr.evaluate(), QVariant("Dog"));
600 object1.setObjectProperty(&object3);
601 QCOMPARE(expr.changed, true);
602 expr.changed = false;
603 QCOMPARE(expr.evaluate(), QVariant("Cat"));
605 object1.setObjectProperty(0);
606 QCOMPARE(expr.changed, true);
607 expr.changed = false;
608 QCOMPARE(expr.evaluate(), QVariant());
610 object1.setObjectProperty(&object3);
611 QCOMPARE(expr.changed, true);
612 expr.changed = false;
613 QCOMPARE(expr.evaluate(), QVariant("Cat"));
615 object3.setStringProperty("Donkey");
616 QCOMPARE(expr.changed, true);
617 expr.changed = false;
618 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
622 void tst_qdeclarativeecmascript::deferredProperties()
624 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
625 MyDeferredObject *object =
626 qobject_cast<MyDeferredObject *>(component.create());
627 QVERIFY(object != 0);
628 QCOMPARE(object->value(), 0);
629 QVERIFY(object->objectProperty() == 0);
630 QVERIFY(object->objectProperty2() != 0);
631 qmlExecuteDeferred(object);
632 QCOMPARE(object->value(), 10);
633 QVERIFY(object->objectProperty() != 0);
634 MyQmlObject *qmlObject =
635 qobject_cast<MyQmlObject *>(object->objectProperty());
636 QVERIFY(qmlObject != 0);
637 QCOMPARE(qmlObject->value(), 10);
638 object->setValue(19);
639 QCOMPARE(qmlObject->value(), 19);
644 // Check errors on deferred properties are correctly emitted
645 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
647 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
648 MyDeferredObject *object =
649 qobject_cast<MyDeferredObject *>(component.create());
650 QVERIFY(object != 0);
651 QCOMPARE(object->value(), 0);
652 QVERIFY(object->objectProperty() == 0);
653 QVERIFY(object->objectProperty2() == 0);
655 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
656 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
658 qmlExecuteDeferred(object);
663 void tst_qdeclarativeecmascript::extensionObjects()
665 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
666 MyExtendedObject *object =
667 qobject_cast<MyExtendedObject *>(component.create());
668 QVERIFY(object != 0);
669 QCOMPARE(object->baseProperty(), 13);
670 QCOMPARE(object->coreProperty(), 9);
671 object->setProperty("extendedProperty", QVariant(11));
672 object->setProperty("baseExtendedProperty", QVariant(92));
673 QCOMPARE(object->coreProperty(), 11);
674 QCOMPARE(object->baseProperty(), 92);
676 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
678 QCOMPARE(nested->baseProperty(), 13);
679 QCOMPARE(nested->coreProperty(), 9);
680 nested->setProperty("extendedProperty", QVariant(11));
681 nested->setProperty("baseExtendedProperty", QVariant(92));
682 QCOMPARE(nested->coreProperty(), 11);
683 QCOMPARE(nested->baseProperty(), 92);
688 void tst_qdeclarativeecmascript::overrideExtensionProperties()
690 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
691 OverrideDefaultPropertyObject *object =
692 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
693 QVERIFY(object != 0);
694 QVERIFY(object->secondProperty() != 0);
695 QVERIFY(object->firstProperty() == 0);
700 void tst_qdeclarativeecmascript::attachedProperties()
703 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
704 QObject *object = component.create();
705 QVERIFY(object != 0);
706 QCOMPARE(object->property("a").toInt(), 19);
707 QCOMPARE(object->property("b").toInt(), 19);
708 QCOMPARE(object->property("c").toInt(), 19);
709 QCOMPARE(object->property("d").toInt(), 19);
714 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
715 QObject *object = component.create();
716 QVERIFY(object != 0);
717 QCOMPARE(object->property("a").toInt(), 26);
718 QCOMPARE(object->property("b").toInt(), 26);
719 QCOMPARE(object->property("c").toInt(), 26);
720 QCOMPARE(object->property("d").toInt(), 26);
726 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
727 QObject *object = component.create();
728 QVERIFY(object != 0);
730 QMetaObject::invokeMethod(object, "writeValue2");
732 MyQmlAttachedObject *attached =
733 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
734 QVERIFY(attached != 0);
736 QCOMPARE(attached->value2(), 9);
741 void tst_qdeclarativeecmascript::enums()
745 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
746 QObject *object = component.create();
747 QVERIFY(object != 0);
749 QCOMPARE(object->property("a").toInt(), 0);
750 QCOMPARE(object->property("b").toInt(), 1);
751 QCOMPARE(object->property("c").toInt(), 2);
752 QCOMPARE(object->property("d").toInt(), 3);
753 QCOMPARE(object->property("e").toInt(), 0);
754 QCOMPARE(object->property("f").toInt(), 1);
755 QCOMPARE(object->property("g").toInt(), 2);
756 QCOMPARE(object->property("h").toInt(), 3);
757 QCOMPARE(object->property("i").toInt(), 19);
758 QCOMPARE(object->property("j").toInt(), 19);
762 // Non-existent enums
764 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
766 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
767 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
768 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
769 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
771 QObject *object = component.create();
772 QVERIFY(object != 0);
773 QCOMPARE(object->property("a").toInt(), 0);
774 QCOMPARE(object->property("b").toInt(), 0);
780 void tst_qdeclarativeecmascript::valueTypeFunctions()
782 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
783 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
785 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
786 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
792 Tests that writing a constant to a property with a binding on it disables the
795 void tst_qdeclarativeecmascript::constantsOverrideBindings()
799 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
800 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
801 QVERIFY(object != 0);
803 QCOMPARE(object->property("c2").toInt(), 0);
804 object->setProperty("c1", QVariant(9));
805 QCOMPARE(object->property("c2").toInt(), 9);
807 emit object->basicSignal();
809 QCOMPARE(object->property("c2").toInt(), 13);
810 object->setProperty("c1", QVariant(8));
811 QCOMPARE(object->property("c2").toInt(), 13);
816 // During construction
818 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
819 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
820 QVERIFY(object != 0);
822 QCOMPARE(object->property("c1").toInt(), 0);
823 QCOMPARE(object->property("c2").toInt(), 10);
824 object->setProperty("c1", QVariant(9));
825 QCOMPARE(object->property("c1").toInt(), 9);
826 QCOMPARE(object->property("c2").toInt(), 10);
834 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
835 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
836 QVERIFY(object != 0);
838 QCOMPARE(object->property("c2").toInt(), 0);
839 object->setProperty("c1", QVariant(9));
840 QCOMPARE(object->property("c2").toInt(), 9);
842 object->setProperty("c2", QVariant(13));
843 QCOMPARE(object->property("c2").toInt(), 13);
844 object->setProperty("c1", QVariant(7));
845 QCOMPARE(object->property("c1").toInt(), 7);
846 QCOMPARE(object->property("c2").toInt(), 13);
854 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
855 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
856 QVERIFY(object != 0);
858 QCOMPARE(object->property("c1").toInt(), 0);
859 QCOMPARE(object->property("c3").toInt(), 10);
860 object->setProperty("c1", QVariant(9));
861 QCOMPARE(object->property("c1").toInt(), 9);
862 QCOMPARE(object->property("c3").toInt(), 10);
869 Tests that assigning a binding to a property that already has a binding causes
870 the original binding to be disabled.
872 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
874 QDeclarativeComponent component(&engine,
875 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
876 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
877 QVERIFY(object != 0);
879 QCOMPARE(object->property("c1").toInt(), 0);
880 QCOMPARE(object->property("c2").toInt(), 0);
881 QCOMPARE(object->property("c3").toInt(), 0);
883 object->setProperty("c1", QVariant(9));
884 QCOMPARE(object->property("c1").toInt(), 9);
885 QCOMPARE(object->property("c2").toInt(), 0);
886 QCOMPARE(object->property("c3").toInt(), 0);
888 object->setProperty("c3", QVariant(8));
889 QCOMPARE(object->property("c1").toInt(), 9);
890 QCOMPARE(object->property("c2").toInt(), 8);
891 QCOMPARE(object->property("c3").toInt(), 8);
897 Access a non-existent attached object.
899 Tests for a regression where this used to crash.
901 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
903 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
905 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
906 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
908 QObject *object = component.create();
909 QVERIFY(object != 0);
914 void tst_qdeclarativeecmascript::scope()
917 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
918 QObject *object = component.create();
919 QVERIFY(object != 0);
921 QCOMPARE(object->property("test1").toInt(), 1);
922 QCOMPARE(object->property("test2").toInt(), 2);
923 QCOMPARE(object->property("test3").toString(), QString("1Test"));
924 QCOMPARE(object->property("test4").toString(), QString("2Test"));
925 QCOMPARE(object->property("test5").toInt(), 1);
926 QCOMPARE(object->property("test6").toInt(), 1);
927 QCOMPARE(object->property("test7").toInt(), 2);
928 QCOMPARE(object->property("test8").toInt(), 2);
929 QCOMPARE(object->property("test9").toInt(), 1);
930 QCOMPARE(object->property("test10").toInt(), 3);
936 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
937 QObject *object = component.create();
938 QVERIFY(object != 0);
940 QCOMPARE(object->property("test1").toInt(), 19);
941 QCOMPARE(object->property("test2").toInt(), 19);
942 QCOMPARE(object->property("test3").toInt(), 14);
943 QCOMPARE(object->property("test4").toInt(), 14);
944 QCOMPARE(object->property("test5").toInt(), 24);
945 QCOMPARE(object->property("test6").toInt(), 24);
951 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
952 QObject *object = component.create();
953 QVERIFY(object != 0);
955 QCOMPARE(object->property("test1").toBool(), true);
956 QCOMPARE(object->property("test2").toBool(), true);
957 QCOMPARE(object->property("test3").toBool(), true);
962 // Signal argument scope
964 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
965 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
966 QVERIFY(object != 0);
968 QCOMPARE(object->property("test").toInt(), 0);
969 QCOMPARE(object->property("test2").toString(), QString());
971 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
973 QCOMPARE(object->property("test").toInt(), 13);
974 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
980 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
981 QObject *object = component.create();
982 QVERIFY(object != 0);
984 QCOMPARE(object->property("test1").toBool(), true);
985 QCOMPARE(object->property("test2").toBool(), true);
991 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
992 QObject *object = component.create();
993 QVERIFY(object != 0);
995 QCOMPARE(object->property("test").toBool(), true);
1001 // In 4.7, non-library javascript files that had no imports shared the imports of their
1002 // importing context
1003 void tst_qdeclarativeecmascript::importScope()
1005 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1006 QObject *o = component.create();
1009 QCOMPARE(o->property("test").toInt(), 240);
1015 Tests that "any" type passes through a synthesized signal parameter. This
1016 is essentially a test of QDeclarativeMetaType::copy()
1018 void tst_qdeclarativeecmascript::signalParameterTypes()
1020 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1021 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1022 QVERIFY(object != 0);
1024 emit object->basicSignal();
1026 QCOMPARE(object->property("intProperty").toInt(), 10);
1027 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1028 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1029 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1030 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1031 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1037 Test that two JS objects for the same QObject compare as equal.
1039 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1041 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1042 QObject *object = component.create();
1043 QVERIFY(object != 0);
1045 QCOMPARE(object->property("test1").toBool(), true);
1046 QCOMPARE(object->property("test2").toBool(), true);
1047 QCOMPARE(object->property("test3").toBool(), true);
1048 QCOMPARE(object->property("test4").toBool(), true);
1049 QCOMPARE(object->property("test5").toBool(), true);
1055 Confirm bindings and alias properties can coexist.
1057 Tests for a regression where the binding would not reevaluate.
1059 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1061 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1062 QObject *object = component.create();
1063 QVERIFY(object != 0);
1065 QCOMPARE(object->property("c2").toInt(), 3);
1066 QCOMPARE(object->property("c3").toInt(), 3);
1068 object->setProperty("c2", QVariant(19));
1070 QCOMPARE(object->property("c2").toInt(), 19);
1071 QCOMPARE(object->property("c3").toInt(), 19);
1077 Ensure that we can write undefined value to an alias property,
1078 and that the aliased property is reset correctly if possible.
1080 void tst_qdeclarativeecmascript::aliasPropertyReset()
1082 QObject *object = 0;
1084 // test that a manual write (of undefined) to a resettable aliased property succeeds
1085 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1086 object = c1.create();
1087 QVERIFY(object != 0);
1088 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1089 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1090 QMetaObject::invokeMethod(object, "resetAliased");
1091 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1092 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1095 // test that a manual write (of undefined) to a resettable alias property succeeds
1096 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1097 object = c2.create();
1098 QVERIFY(object != 0);
1099 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1100 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1101 QMetaObject::invokeMethod(object, "resetAlias");
1102 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1103 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1106 // test that an alias to a bound property works correctly
1107 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1108 object = c3.create();
1109 QVERIFY(object != 0);
1110 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1111 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1112 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1113 QMetaObject::invokeMethod(object, "resetAlias");
1114 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1115 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1116 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1119 // test that a manual write (of undefined) to a resettable alias property
1120 // whose aliased property's object has been deleted, does not crash.
1121 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1122 object = c4.create();
1123 QVERIFY(object != 0);
1124 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1125 QObject *loader = object->findChild<QObject*>("loader");
1126 QVERIFY(loader != 0);
1128 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1129 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1130 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1131 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1132 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1135 // test that binding an alias property to an undefined value works correctly
1136 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1137 object = c5.create();
1138 QVERIFY(object != 0);
1139 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1142 // test that a manual write (of undefined) to a non-resettable property fails properly
1143 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1144 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1145 QDeclarativeComponent e1(&engine, url);
1146 object = e1.create();
1147 QVERIFY(object != 0);
1148 QCOMPARE(object->property("intAlias").value<int>(), 12);
1149 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1150 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1151 QMetaObject::invokeMethod(object, "resetAlias");
1152 QCOMPARE(object->property("intAlias").value<int>(), 12);
1153 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1157 void tst_qdeclarativeecmascript::dynamicCreation_data()
1159 QTest::addColumn<QString>("method");
1160 QTest::addColumn<QString>("createdName");
1162 QTest::newRow("One") << "createOne" << "objectOne";
1163 QTest::newRow("Two") << "createTwo" << "objectTwo";
1164 QTest::newRow("Three") << "createThree" << "objectThree";
1168 Test using createQmlObject to dynamically generate an item
1169 Also using createComponent is tested.
1171 void tst_qdeclarativeecmascript::dynamicCreation()
1173 QFETCH(QString, method);
1174 QFETCH(QString, createdName);
1176 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1177 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1178 QVERIFY(object != 0);
1180 QMetaObject::invokeMethod(object, method.toUtf8());
1181 QObject *created = object->objectProperty();
1183 QCOMPARE(created->objectName(), createdName);
1189 Tests the destroy function
1191 void tst_qdeclarativeecmascript::dynamicDestruction()
1194 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1195 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1196 QVERIFY(object != 0);
1197 QDeclarativeGuard<QObject> createdQmlObject = 0;
1199 QMetaObject::invokeMethod(object, "create");
1200 createdQmlObject = object->objectProperty();
1201 QVERIFY(createdQmlObject);
1202 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1204 QMetaObject::invokeMethod(object, "killOther");
1205 QVERIFY(createdQmlObject);
1206 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1207 QVERIFY(createdQmlObject);
1208 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1209 if (createdQmlObject) {
1211 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1214 QVERIFY(!createdQmlObject);
1216 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1217 QMetaObject::invokeMethod(object, "killMe");
1220 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1225 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1226 QObject *o = component.create();
1229 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1231 QMetaObject::invokeMethod(o, "create");
1233 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1235 QMetaObject::invokeMethod(o, "destroy");
1237 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1239 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1246 tests that id.toString() works
1248 void tst_qdeclarativeecmascript::objectToString()
1250 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1251 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1252 QVERIFY(object != 0);
1253 QMetaObject::invokeMethod(object, "testToString");
1254 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1255 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1261 tests that id.hasOwnProperty() works
1263 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1265 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1266 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1267 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1268 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1270 QDeclarativeComponent component(&engine, url);
1271 QObject *object = component.create();
1272 QVERIFY(object != 0);
1274 // test QObjects in QML
1275 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1276 QVERIFY(object->property("result").value<bool>() == true);
1277 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1278 QVERIFY(object->property("result").value<bool>() == false);
1280 // now test other types in QML
1281 QObject *child = object->findChild<QObject*>("typeObj");
1282 QVERIFY(child != 0);
1283 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1284 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1285 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1286 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1287 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1288 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1289 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1290 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1291 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1292 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1293 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1294 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1296 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1297 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1298 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1299 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1300 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1301 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1302 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1303 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1304 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1310 Tests bindings that indirectly cause their own deletion work.
1312 This test is best run under valgrind to ensure no invalid memory access occur.
1314 void tst_qdeclarativeecmascript::selfDeletingBinding()
1317 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1318 QObject *object = component.create();
1319 QVERIFY(object != 0);
1320 object->setProperty("triggerDelete", true);
1325 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1326 QObject *object = component.create();
1327 QVERIFY(object != 0);
1328 object->setProperty("triggerDelete", true);
1334 Test that extended object properties can be accessed.
1336 This test a regression where this used to crash. The issue was specificially
1337 for extended objects that did not include a synthesized meta object (so non-root
1338 and no synthesiszed properties).
1340 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1342 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1343 QObject *object = component.create();
1344 QVERIFY(object != 0);
1349 Test file/lineNumbers for binding/Script errors.
1351 void tst_qdeclarativeecmascript::scriptErrors()
1353 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1354 QString url = component.url().toString();
1356 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1357 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1358 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1359 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1360 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1361 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1362 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1363 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1365 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1366 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1367 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1368 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1369 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1370 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1371 QVERIFY(object != 0);
1373 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1374 emit object->basicSignal();
1376 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1377 emit object->anotherBasicSignal();
1379 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1380 emit object->thirdBasicSignal();
1386 Test file/lineNumbers for inline functions.
1388 void tst_qdeclarativeecmascript::functionErrors()
1390 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1391 QString url = component.url().toString();
1393 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1395 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1397 QObject *object = component.create();
1398 QVERIFY(object != 0);
1401 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1402 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1403 url = componentTwo.url().toString();
1404 object = componentTwo.create();
1405 QVERIFY(object != 0);
1407 QString srpname = object->property("srp_name").toString();
1409 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1410 QLatin1String(" is not a function");
1411 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1412 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1417 Test various errors that can occur when assigning a property from script
1419 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1421 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1423 QString url = component.url().toString();
1425 QObject *object = component.create();
1426 QVERIFY(object != 0);
1428 QCOMPARE(object->property("test1").toBool(), true);
1429 QCOMPARE(object->property("test2").toBool(), true);
1435 Test bindings still work when the reeval is triggered from within
1438 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1440 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1441 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1442 QVERIFY(object != 0);
1444 QCOMPARE(object->property("base").toReal(), 50.);
1445 QCOMPARE(object->property("test1").toReal(), 50.);
1446 QCOMPARE(object->property("test2").toReal(), 50.);
1448 object->basicSignal();
1450 QCOMPARE(object->property("base").toReal(), 200.);
1451 QCOMPARE(object->property("test1").toReal(), 200.);
1452 QCOMPARE(object->property("test2").toReal(), 200.);
1454 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1456 QCOMPARE(object->property("base").toReal(), 400.);
1457 QCOMPARE(object->property("test1").toReal(), 400.);
1458 QCOMPARE(object->property("test2").toReal(), 400.);
1464 Test that list properties can be iterated from ECMAScript
1466 void tst_qdeclarativeecmascript::listProperties()
1468 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1469 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1470 QVERIFY(object != 0);
1472 QCOMPARE(object->property("test1").toInt(), 21);
1473 QCOMPARE(object->property("test2").toInt(), 2);
1474 QCOMPARE(object->property("test3").toBool(), true);
1475 QCOMPARE(object->property("test4").toBool(), true);
1480 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1482 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1483 QString url = component.url().toString();
1485 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1487 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1488 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1489 QVERIFY(object != 0);
1491 QCOMPARE(object->property("test").toBool(), false);
1493 MyQmlObject object2;
1494 MyQmlObject object3;
1495 object2.setObjectProperty(&object3);
1496 object->setObjectProperty(&object2);
1498 QCOMPARE(object->property("test").toBool(), true);
1503 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1505 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1506 QString url = component.url().toString();
1508 QString warning = component.url().toString() + ":6: Error: JS exception";
1510 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1511 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1512 QVERIFY(object != 0);
1516 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1518 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1519 QString url = component.url().toString();
1521 QString warning = component.url().toString() + ":5: Error: JS exception";
1523 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1524 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1525 QVERIFY(object != 0);
1529 static int transientErrorsMsgCount = 0;
1530 static void transientErrorsMsgHandler(QtMsgType, const char *)
1532 ++transientErrorsMsgCount;
1535 // Check that transient binding errors are not displayed
1536 void tst_qdeclarativeecmascript::transientErrors()
1539 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1541 transientErrorsMsgCount = 0;
1542 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1544 QObject *object = component.create();
1545 QVERIFY(object != 0);
1547 qInstallMsgHandler(old);
1549 QCOMPARE(transientErrorsMsgCount, 0);
1554 // One binding erroring multiple times, but then resolving
1556 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1558 transientErrorsMsgCount = 0;
1559 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1561 QObject *object = component.create();
1562 QVERIFY(object != 0);
1564 qInstallMsgHandler(old);
1566 QCOMPARE(transientErrorsMsgCount, 0);
1572 // Check that errors during shutdown are minimized
1573 void tst_qdeclarativeecmascript::shutdownErrors()
1575 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1576 QObject *object = component.create();
1577 QVERIFY(object != 0);
1579 transientErrorsMsgCount = 0;
1580 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1584 qInstallMsgHandler(old);
1585 QCOMPARE(transientErrorsMsgCount, 0);
1588 void tst_qdeclarativeecmascript::compositePropertyType()
1590 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1591 QTest::ignoreMessage(QtDebugMsg, "hello world");
1592 QObject *object = qobject_cast<QObject *>(component.create());
1597 void tst_qdeclarativeecmascript::jsObject()
1599 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1600 QObject *object = component.create();
1601 QVERIFY(object != 0);
1603 QCOMPARE(object->property("test").toInt(), 92);
1608 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1611 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1612 QObject *object = component.create();
1613 QVERIFY(object != 0);
1615 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1617 object->setProperty("setUndefined", true);
1619 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1621 object->setProperty("setUndefined", false);
1623 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1628 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1629 QObject *object = component.create();
1630 QVERIFY(object != 0);
1632 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1634 QMetaObject::invokeMethod(object, "doReset");
1636 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1643 void tst_qdeclarativeecmascript::bug1()
1645 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1646 QObject *object = component.create();
1647 QVERIFY(object != 0);
1649 QCOMPARE(object->property("test").toInt(), 14);
1651 object->setProperty("a", 11);
1653 QCOMPARE(object->property("test").toInt(), 3);
1655 object->setProperty("b", true);
1657 QCOMPARE(object->property("test").toInt(), 9);
1662 void tst_qdeclarativeecmascript::bug2()
1664 QDeclarativeComponent component(&engine);
1665 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1667 QObject *object = component.create();
1668 QVERIFY(object != 0);
1673 // Don't crash in createObject when the component has errors.
1674 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1676 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1677 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1678 QVERIFY(object != 0);
1680 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1681 QMetaObject::invokeMethod(object, "dontCrash");
1682 QObject *created = object->objectProperty();
1683 QVERIFY(created == 0);
1688 // ownership transferred to JS, ensure that GC runs the dtor
1689 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1692 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1694 // allow the engine to go out of scope too.
1696 QDeclarativeEngine dcoEngine;
1697 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1698 QObject *object = component.create();
1699 QVERIFY(object != 0);
1700 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1701 QVERIFY(mdcdo != 0);
1702 mdcdo->setDtorCount(&dtorCount);
1704 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1705 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1707 // we do this once manually, but it should be done automatically
1708 // when the engine goes out of scope (since it should gc in dtor)
1709 QMetaObject::invokeMethod(object, "performGc");
1712 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1718 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1719 QCOMPARE(dtorCount, expectedDtorCount);
1723 void tst_qdeclarativeecmascript::regExpBug()
1725 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1726 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1727 QVERIFY(object != 0);
1728 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1732 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1734 QString functionSource = QLatin1String("(function(object) { return ") +
1735 QLatin1String(source) + QLatin1String(" })");
1737 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1740 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1741 if (function.IsEmpty())
1743 v8::Handle<v8::Value> args[] = { o };
1744 function->Call(engine->global(), 1, args);
1745 return tc.HasCaught();
1748 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1749 const char *source, v8::Handle<v8::Value> result)
1751 QString functionSource = QLatin1String("(function(object) { return ") +
1752 QLatin1String(source) + QLatin1String(" })");
1754 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1757 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1758 if (function.IsEmpty())
1760 v8::Handle<v8::Value> args[] = { o };
1762 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1767 return value->StrictEquals(result);
1770 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1773 QString functionSource = QLatin1String("(function(object) { return ") +
1774 QLatin1String(source) + QLatin1String(" })");
1776 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1778 return v8::Handle<v8::Value>();
1779 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1780 if (function.IsEmpty())
1781 return v8::Handle<v8::Value>();
1782 v8::Handle<v8::Value> args[] = { o };
1784 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1787 return v8::Handle<v8::Value>();
1791 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1792 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1793 #define EVALUATE(source) evaluate(engine, object, source)
1795 void tst_qdeclarativeecmascript::callQtInvokables()
1797 MyInvokableObject o;
1799 QDeclarativeEngine qmlengine;
1800 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1802 QV8Engine *engine = ep->v8engine();
1804 v8::HandleScope handle_scope;
1805 v8::Context::Scope scope(engine->context());
1807 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1809 // Non-existent methods
1811 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1812 QCOMPARE(o.error(), false);
1813 QCOMPARE(o.invoked(), -1);
1814 QCOMPARE(o.actuals().count(), 0);
1817 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1818 QCOMPARE(o.error(), false);
1819 QCOMPARE(o.invoked(), -1);
1820 QCOMPARE(o.actuals().count(), 0);
1822 // Insufficient arguments
1824 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1825 QCOMPARE(o.error(), false);
1826 QCOMPARE(o.invoked(), -1);
1827 QCOMPARE(o.actuals().count(), 0);
1830 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1831 QCOMPARE(o.error(), false);
1832 QCOMPARE(o.invoked(), -1);
1833 QCOMPARE(o.actuals().count(), 0);
1835 // Excessive arguments
1837 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1838 QCOMPARE(o.error(), false);
1839 QCOMPARE(o.invoked(), 8);
1840 QCOMPARE(o.actuals().count(), 1);
1841 QCOMPARE(o.actuals().at(0), QVariant(10));
1844 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1845 QCOMPARE(o.error(), false);
1846 QCOMPARE(o.invoked(), 9);
1847 QCOMPARE(o.actuals().count(), 2);
1848 QCOMPARE(o.actuals().at(0), QVariant(10));
1849 QCOMPARE(o.actuals().at(1), QVariant(11));
1851 // Test return types
1853 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1854 QCOMPARE(o.error(), false);
1855 QCOMPARE(o.invoked(), 0);
1856 QCOMPARE(o.actuals().count(), 0);
1859 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1860 QCOMPARE(o.error(), false);
1861 QCOMPARE(o.invoked(), 1);
1862 QCOMPARE(o.actuals().count(), 0);
1865 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1866 QCOMPARE(o.error(), false);
1867 QCOMPARE(o.invoked(), 2);
1868 QCOMPARE(o.actuals().count(), 0);
1872 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1873 QVERIFY(!ret.IsEmpty());
1874 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1875 QCOMPARE(o.error(), false);
1876 QCOMPARE(o.invoked(), 3);
1877 QCOMPARE(o.actuals().count(), 0);
1882 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1883 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1884 QCOMPARE(o.error(), false);
1885 QCOMPARE(o.invoked(), 4);
1886 QCOMPARE(o.actuals().count(), 0);
1890 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1891 QCOMPARE(o.error(), false);
1892 QCOMPARE(o.invoked(), 5);
1893 QCOMPARE(o.actuals().count(), 0);
1897 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1898 QVERIFY(ret->IsString());
1899 QCOMPARE(engine->toString(ret), QString("Hello world"));
1900 QCOMPARE(o.error(), false);
1901 QCOMPARE(o.invoked(), 6);
1902 QCOMPARE(o.actuals().count(), 0);
1906 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1907 QCOMPARE(o.error(), false);
1908 QCOMPARE(o.invoked(), 7);
1909 QCOMPARE(o.actuals().count(), 0);
1913 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1914 QCOMPARE(o.error(), false);
1915 QCOMPARE(o.invoked(), 8);
1916 QCOMPARE(o.actuals().count(), 1);
1917 QCOMPARE(o.actuals().at(0), QVariant(94));
1920 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1921 QCOMPARE(o.error(), false);
1922 QCOMPARE(o.invoked(), 8);
1923 QCOMPARE(o.actuals().count(), 1);
1924 QCOMPARE(o.actuals().at(0), QVariant(94));
1927 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1928 QCOMPARE(o.error(), false);
1929 QCOMPARE(o.invoked(), 8);
1930 QCOMPARE(o.actuals().count(), 1);
1931 QCOMPARE(o.actuals().at(0), QVariant(0));
1934 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1935 QCOMPARE(o.error(), false);
1936 QCOMPARE(o.invoked(), 8);
1937 QCOMPARE(o.actuals().count(), 1);
1938 QCOMPARE(o.actuals().at(0), QVariant(0));
1941 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1942 QCOMPARE(o.error(), false);
1943 QCOMPARE(o.invoked(), 8);
1944 QCOMPARE(o.actuals().count(), 1);
1945 QCOMPARE(o.actuals().at(0), QVariant(0));
1948 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1949 QCOMPARE(o.error(), false);
1950 QCOMPARE(o.invoked(), 8);
1951 QCOMPARE(o.actuals().count(), 1);
1952 QCOMPARE(o.actuals().at(0), QVariant(0));
1955 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1956 QCOMPARE(o.error(), false);
1957 QCOMPARE(o.invoked(), 9);
1958 QCOMPARE(o.actuals().count(), 2);
1959 QCOMPARE(o.actuals().at(0), QVariant(122));
1960 QCOMPARE(o.actuals().at(1), QVariant(9));
1963 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1964 QCOMPARE(o.error(), false);
1965 QCOMPARE(o.invoked(), 10);
1966 QCOMPARE(o.actuals().count(), 1);
1967 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1970 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1971 QCOMPARE(o.error(), false);
1972 QCOMPARE(o.invoked(), 10);
1973 QCOMPARE(o.actuals().count(), 1);
1974 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1977 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1978 QCOMPARE(o.error(), false);
1979 QCOMPARE(o.invoked(), 10);
1980 QCOMPARE(o.actuals().count(), 1);
1981 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1984 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1985 QCOMPARE(o.error(), false);
1986 QCOMPARE(o.invoked(), 10);
1987 QCOMPARE(o.actuals().count(), 1);
1988 QCOMPARE(o.actuals().at(0), QVariant(0));
1991 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1992 QCOMPARE(o.error(), false);
1993 QCOMPARE(o.invoked(), 10);
1994 QCOMPARE(o.actuals().count(), 1);
1995 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1998 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1999 QCOMPARE(o.error(), false);
2000 QCOMPARE(o.invoked(), 10);
2001 QCOMPARE(o.actuals().count(), 1);
2002 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2005 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2006 QCOMPARE(o.error(), false);
2007 QCOMPARE(o.invoked(), 11);
2008 QCOMPARE(o.actuals().count(), 1);
2009 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2012 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2013 QCOMPARE(o.error(), false);
2014 QCOMPARE(o.invoked(), 11);
2015 QCOMPARE(o.actuals().count(), 1);
2016 QCOMPARE(o.actuals().at(0), QVariant("19"));
2020 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2021 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2022 QCOMPARE(o.error(), false);
2023 QCOMPARE(o.invoked(), 11);
2024 QCOMPARE(o.actuals().count(), 1);
2025 QCOMPARE(o.actuals().at(0), QVariant(expected));
2029 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2030 QCOMPARE(o.error(), false);
2031 QCOMPARE(o.invoked(), 11);
2032 QCOMPARE(o.actuals().count(), 1);
2033 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2036 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2037 QCOMPARE(o.error(), false);
2038 QCOMPARE(o.invoked(), 11);
2039 QCOMPARE(o.actuals().count(), 1);
2040 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2043 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2044 QCOMPARE(o.error(), false);
2045 QCOMPARE(o.invoked(), 12);
2046 QCOMPARE(o.actuals().count(), 1);
2047 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2050 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2051 QCOMPARE(o.error(), false);
2052 QCOMPARE(o.invoked(), 12);
2053 QCOMPARE(o.actuals().count(), 1);
2054 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2057 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2058 QCOMPARE(o.error(), false);
2059 QCOMPARE(o.invoked(), 12);
2060 QCOMPARE(o.actuals().count(), 1);
2061 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2064 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2065 QCOMPARE(o.error(), false);
2066 QCOMPARE(o.invoked(), 12);
2067 QCOMPARE(o.actuals().count(), 1);
2068 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2071 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2072 QCOMPARE(o.error(), false);
2073 QCOMPARE(o.invoked(), 12);
2074 QCOMPARE(o.actuals().count(), 1);
2075 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2078 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2079 QCOMPARE(o.error(), false);
2080 QCOMPARE(o.invoked(), 12);
2081 QCOMPARE(o.actuals().count(), 1);
2082 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2085 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2086 QCOMPARE(o.error(), false);
2087 QCOMPARE(o.invoked(), 13);
2088 QCOMPARE(o.actuals().count(), 1);
2089 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2092 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2093 QCOMPARE(o.error(), false);
2094 QCOMPARE(o.invoked(), 13);
2095 QCOMPARE(o.actuals().count(), 1);
2096 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2099 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2100 QCOMPARE(o.error(), false);
2101 QCOMPARE(o.invoked(), 13);
2102 QCOMPARE(o.actuals().count(), 1);
2103 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2106 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2107 QCOMPARE(o.error(), false);
2108 QCOMPARE(o.invoked(), 13);
2109 QCOMPARE(o.actuals().count(), 1);
2110 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2113 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2114 QCOMPARE(o.error(), false);
2115 QCOMPARE(o.invoked(), 13);
2116 QCOMPARE(o.actuals().count(), 1);
2117 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2120 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2121 QCOMPARE(o.error(), false);
2122 QCOMPARE(o.invoked(), 14);
2123 QCOMPARE(o.actuals().count(), 1);
2124 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2127 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2128 QCOMPARE(o.error(), false);
2129 QCOMPARE(o.invoked(), 14);
2130 QCOMPARE(o.actuals().count(), 1);
2131 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2134 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2135 QCOMPARE(o.error(), false);
2136 QCOMPARE(o.invoked(), 14);
2137 QCOMPARE(o.actuals().count(), 1);
2138 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2141 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2142 QCOMPARE(o.error(), false);
2143 QCOMPARE(o.invoked(), 14);
2144 QCOMPARE(o.actuals().count(), 1);
2145 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2148 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2149 QCOMPARE(o.error(), false);
2150 QCOMPARE(o.invoked(), 15);
2151 QCOMPARE(o.actuals().count(), 2);
2152 QCOMPARE(o.actuals().at(0), QVariant(4));
2153 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2156 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2157 QCOMPARE(o.error(), false);
2158 QCOMPARE(o.invoked(), 15);
2159 QCOMPARE(o.actuals().count(), 2);
2160 QCOMPARE(o.actuals().at(0), QVariant(8));
2161 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2164 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2165 QCOMPARE(o.error(), false);
2166 QCOMPARE(o.invoked(), 15);
2167 QCOMPARE(o.actuals().count(), 2);
2168 QCOMPARE(o.actuals().at(0), QVariant(3));
2169 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2172 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2173 QCOMPARE(o.error(), false);
2174 QCOMPARE(o.invoked(), 15);
2175 QCOMPARE(o.actuals().count(), 2);
2176 QCOMPARE(o.actuals().at(0), QVariant(44));
2177 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2180 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2181 QCOMPARE(o.error(), false);
2182 QCOMPARE(o.invoked(), -1);
2183 QCOMPARE(o.actuals().count(), 0);
2186 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2187 QCOMPARE(o.error(), false);
2188 QCOMPARE(o.invoked(), 16);
2189 QCOMPARE(o.actuals().count(), 1);
2190 QCOMPARE(o.actuals().at(0), QVariant(10));
2193 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2194 QCOMPARE(o.error(), false);
2195 QCOMPARE(o.invoked(), 17);
2196 QCOMPARE(o.actuals().count(), 2);
2197 QCOMPARE(o.actuals().at(0), QVariant(10));
2198 QCOMPARE(o.actuals().at(1), QVariant(11));
2201 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2202 QCOMPARE(o.error(), false);
2203 QCOMPARE(o.invoked(), 18);
2204 QCOMPARE(o.actuals().count(), 1);
2205 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2208 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2209 QCOMPARE(o.error(), false);
2210 QCOMPARE(o.invoked(), 19);
2211 QCOMPARE(o.actuals().count(), 1);
2212 QCOMPARE(o.actuals().at(0), QVariant(9));
2215 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2216 QCOMPARE(o.error(), false);
2217 QCOMPARE(o.invoked(), 20);
2218 QCOMPARE(o.actuals().count(), 2);
2219 QCOMPARE(o.actuals().at(0), QVariant(10));
2220 QCOMPARE(o.actuals().at(1), QVariant(19));
2223 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2224 QCOMPARE(o.error(), false);
2225 QCOMPARE(o.invoked(), 20);
2226 QCOMPARE(o.actuals().count(), 2);
2227 QCOMPARE(o.actuals().at(0), QVariant(10));
2228 QCOMPARE(o.actuals().at(1), QVariant(13));
2231 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2232 QCOMPARE(o.error(), false);
2233 QCOMPARE(o.invoked(), -3);
2234 QCOMPARE(o.actuals().count(), 1);
2235 QCOMPARE(o.actuals().at(0), QVariant(9));
2238 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2239 QCOMPARE(o.error(), false);
2240 QCOMPARE(o.invoked(), 21);
2241 QCOMPARE(o.actuals().count(), 2);
2242 QCOMPARE(o.actuals().at(0), QVariant(9));
2243 QCOMPARE(o.actuals().at(1), QVariant());
2246 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2247 QCOMPARE(o.error(), false);
2248 QCOMPARE(o.invoked(), 21);
2249 QCOMPARE(o.actuals().count(), 2);
2250 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2251 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2254 // QTBUG-13047 (check that you can pass registered object types as args)
2255 void tst_qdeclarativeecmascript::invokableObjectArg()
2257 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2259 QObject *o = component.create();
2261 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2263 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2268 // QTBUG-13047 (check that you can return registered object types from methods)
2269 void tst_qdeclarativeecmascript::invokableObjectRet()
2271 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2273 QObject *o = component.create();
2275 QCOMPARE(o->property("test").toBool(), true);
2280 void tst_qdeclarativeecmascript::listToVariant()
2282 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2284 MyQmlContainer container;
2286 QDeclarativeContext context(engine.rootContext());
2287 context.setContextObject(&container);
2289 QObject *object = component.create(&context);
2290 QVERIFY(object != 0);
2292 QVariant v = object->property("test");
2293 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2294 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2300 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2301 void tst_qdeclarativeecmascript::listAssignment()
2303 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2304 QObject *obj = component.create();
2305 QCOMPARE(obj->property("list1length").toInt(), 2);
2306 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2307 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2308 QCOMPARE(list1.count(&list1), list2.count(&list2));
2309 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2310 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2315 void tst_qdeclarativeecmascript::multiEngineObject()
2318 obj.setStringProperty("Howdy planet");
2320 QDeclarativeEngine e1;
2321 e1.rootContext()->setContextProperty("thing", &obj);
2322 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2324 QDeclarativeEngine e2;
2325 e2.rootContext()->setContextProperty("thing", &obj);
2326 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2328 QObject *o1 = c1.create();
2329 QObject *o2 = c2.create();
2331 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2332 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2338 // Test that references to QObjects are cleanup when the object is destroyed
2339 void tst_qdeclarativeecmascript::deletedObject()
2341 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2343 QObject *object = component.create();
2345 QCOMPARE(object->property("test1").toBool(), true);
2346 QCOMPARE(object->property("test2").toBool(), true);
2347 QCOMPARE(object->property("test3").toBool(), true);
2348 QCOMPARE(object->property("test4").toBool(), true);
2353 void tst_qdeclarativeecmascript::attachedPropertyScope()
2355 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2357 QObject *object = component.create();
2358 QVERIFY(object != 0);
2360 MyQmlAttachedObject *attached =
2361 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2362 QVERIFY(attached != 0);
2364 QCOMPARE(object->property("value2").toInt(), 0);
2366 attached->emitMySignal();
2368 QCOMPARE(object->property("value2").toInt(), 9);
2373 void tst_qdeclarativeecmascript::scriptConnect()
2376 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2378 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2379 QVERIFY(object != 0);
2381 QCOMPARE(object->property("test").toBool(), false);
2382 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2383 QCOMPARE(object->property("test").toBool(), true);
2389 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2391 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2392 QVERIFY(object != 0);
2394 QCOMPARE(object->property("test").toBool(), false);
2395 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2396 QCOMPARE(object->property("test").toBool(), true);
2402 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2404 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2405 QVERIFY(object != 0);
2407 QCOMPARE(object->property("test").toBool(), false);
2408 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2409 QCOMPARE(object->property("test").toBool(), true);
2415 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2417 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2418 QVERIFY(object != 0);
2420 QCOMPARE(object->methodCalled(), false);
2421 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2422 QCOMPARE(object->methodCalled(), true);
2428 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2430 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2431 QVERIFY(object != 0);
2433 QCOMPARE(object->methodCalled(), false);
2434 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2435 QCOMPARE(object->methodCalled(), true);
2441 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2443 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2444 QVERIFY(object != 0);
2446 QCOMPARE(object->property("test").toInt(), 0);
2447 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2448 QCOMPARE(object->property("test").toInt(), 2);
2454 void tst_qdeclarativeecmascript::scriptDisconnect()
2457 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2459 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2460 QVERIFY(object != 0);
2462 QCOMPARE(object->property("test").toInt(), 0);
2463 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2464 QCOMPARE(object->property("test").toInt(), 1);
2465 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2466 QCOMPARE(object->property("test").toInt(), 2);
2467 emit object->basicSignal();
2468 QCOMPARE(object->property("test").toInt(), 2);
2469 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2470 QCOMPARE(object->property("test").toInt(), 2);
2476 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2478 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2479 QVERIFY(object != 0);
2481 QCOMPARE(object->property("test").toInt(), 0);
2482 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2483 QCOMPARE(object->property("test").toInt(), 1);
2484 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2485 QCOMPARE(object->property("test").toInt(), 2);
2486 emit object->basicSignal();
2487 QCOMPARE(object->property("test").toInt(), 2);
2488 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2489 QCOMPARE(object->property("test").toInt(), 2);
2495 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2497 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2498 QVERIFY(object != 0);
2500 QCOMPARE(object->property("test").toInt(), 0);
2501 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2502 QCOMPARE(object->property("test").toInt(), 1);
2503 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2504 QCOMPARE(object->property("test").toInt(), 2);
2505 emit object->basicSignal();
2506 QCOMPARE(object->property("test").toInt(), 2);
2507 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2508 QCOMPARE(object->property("test").toInt(), 3);
2513 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2515 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2516 QVERIFY(object != 0);
2518 QCOMPARE(object->property("test").toInt(), 0);
2519 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2520 QCOMPARE(object->property("test").toInt(), 1);
2521 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2522 QCOMPARE(object->property("test").toInt(), 2);
2523 emit object->basicSignal();
2524 QCOMPARE(object->property("test").toInt(), 2);
2525 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2526 QCOMPARE(object->property("test").toInt(), 3);
2532 class OwnershipObject : public QObject
2536 OwnershipObject() { object = new QObject; }
2538 QPointer<QObject> object;
2541 QObject *getObject() { return object; }
2544 void tst_qdeclarativeecmascript::ownership()
2546 OwnershipObject own;
2547 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2548 context->setContextObject(&own);
2551 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2553 QVERIFY(own.object != 0);
2555 QObject *object = component.create(context);
2557 engine.collectGarbage();
2559 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2561 QVERIFY(own.object == 0);
2566 own.object = new QObject(&own);
2569 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2571 QVERIFY(own.object != 0);
2573 QObject *object = component.create(context);
2575 engine.collectGarbage();
2577 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2579 QVERIFY(own.object != 0);
2587 class CppOwnershipReturnValue : public QObject
2591 CppOwnershipReturnValue() : value(0) {}
2592 ~CppOwnershipReturnValue() { delete value; }
2594 Q_INVOKABLE QObject *create() {
2595 value = new QObject;
2596 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2600 Q_INVOKABLE MyQmlObject *createQmlObject() {
2601 MyQmlObject *rv = new MyQmlObject;
2606 QPointer<QObject> value;
2610 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2611 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2613 CppOwnershipReturnValue source;
2616 QDeclarativeEngine engine;
2617 engine.rootContext()->setContextProperty("source", &source);
2619 QVERIFY(source.value == 0);
2621 QDeclarativeComponent component(&engine);
2622 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2624 QObject *object = component.create();
2626 QVERIFY(object != 0);
2627 QVERIFY(source.value != 0);
2632 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2634 QVERIFY(source.value != 0);
2638 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2640 CppOwnershipReturnValue source;
2643 QDeclarativeEngine engine;
2644 engine.rootContext()->setContextProperty("source", &source);
2646 QVERIFY(source.value == 0);
2648 QDeclarativeComponent component(&engine);
2649 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2651 QObject *object = component.create();
2653 QVERIFY(object != 0);
2654 QVERIFY(source.value != 0);
2659 engine.collectGarbage();
2660 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2662 QVERIFY(source.value == 0);
2665 class QListQObjectMethodsObject : public QObject
2669 QListQObjectMethodsObject() {
2670 m_objects.append(new MyQmlObject());
2671 m_objects.append(new MyQmlObject());
2674 ~QListQObjectMethodsObject() {
2675 qDeleteAll(m_objects);
2679 QList<QObject *> getObjects() { return m_objects; }
2682 QList<QObject *> m_objects;
2685 // Tests that returning a QList<QObject*> from a method works
2686 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2688 QListQObjectMethodsObject obj;
2689 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2690 context->setContextObject(&obj);
2692 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2694 QObject *object = component.create(context);
2696 QCOMPARE(object->property("test").toInt(), 2);
2697 QCOMPARE(object->property("test2").toBool(), true);
2704 void tst_qdeclarativeecmascript::strictlyEquals()
2706 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2708 QObject *object = component.create();
2709 QVERIFY(object != 0);
2711 QCOMPARE(object->property("test1").toBool(), true);
2712 QCOMPARE(object->property("test2").toBool(), true);
2713 QCOMPARE(object->property("test3").toBool(), true);
2714 QCOMPARE(object->property("test4").toBool(), true);
2715 QCOMPARE(object->property("test5").toBool(), true);
2716 QCOMPARE(object->property("test6").toBool(), true);
2717 QCOMPARE(object->property("test7").toBool(), true);
2718 QCOMPARE(object->property("test8").toBool(), true);
2723 void tst_qdeclarativeecmascript::compiled()
2725 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2727 QObject *object = component.create();
2728 QVERIFY(object != 0);
2730 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2731 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2732 QCOMPARE(object->property("test3").toBool(), true);
2733 QCOMPARE(object->property("test4").toBool(), false);
2734 QCOMPARE(object->property("test5").toBool(), false);
2735 QCOMPARE(object->property("test6").toBool(), true);
2737 QCOMPARE(object->property("test7").toInt(), 185);
2738 QCOMPARE(object->property("test8").toInt(), 167);
2739 QCOMPARE(object->property("test9").toBool(), true);
2740 QCOMPARE(object->property("test10").toBool(), false);
2741 QCOMPARE(object->property("test11").toBool(), false);
2742 QCOMPARE(object->property("test12").toBool(), true);
2744 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2745 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2746 QCOMPARE(object->property("test15").toBool(), false);
2747 QCOMPARE(object->property("test16").toBool(), true);
2749 QCOMPARE(object->property("test17").toInt(), 5);
2750 QCOMPARE(object->property("test18").toReal(), qreal(176));
2751 QCOMPARE(object->property("test19").toInt(), 7);
2752 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2753 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2754 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2755 QCOMPARE(object->property("test23").toBool(), true);
2756 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2757 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2762 // Test that numbers assigned in bindings as strings work consistently
2763 void tst_qdeclarativeecmascript::numberAssignment()
2765 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2767 QObject *object = component.create();
2768 QVERIFY(object != 0);
2770 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2771 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2772 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2773 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2774 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2776 QCOMPARE(object->property("test5"), QVariant((int)7));
2777 QCOMPARE(object->property("test6"), QVariant((int)7));
2778 QCOMPARE(object->property("test7"), QVariant((int)6));
2779 QCOMPARE(object->property("test8"), QVariant((int)6));
2781 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2782 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2783 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2784 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2789 void tst_qdeclarativeecmascript::propertySplicing()
2791 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2793 QObject *object = component.create();
2794 QVERIFY(object != 0);
2796 QCOMPARE(object->property("test").toBool(), true);
2802 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2804 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2806 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2807 QVERIFY(object != 0);
2809 MyQmlObject::MyType type;
2810 type.value = 0x8971123;
2811 emit object->signalWithUnknownType(type);
2813 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2815 QCOMPARE(result.value, type.value);
2821 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2823 QTest::addColumn<QString>("expression");
2824 QTest::addColumn<QString>("compare");
2826 QString compareStrict("(function(a, b) { return a === b; })");
2827 QTest::newRow("true") << "true" << compareStrict;
2828 QTest::newRow("undefined") << "undefined" << compareStrict;
2829 QTest::newRow("null") << "null" << compareStrict;
2830 QTest::newRow("123") << "123" << compareStrict;
2831 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2833 QString comparePropertiesStrict(
2835 " if (typeof b != 'object')"
2837 " var props = Object.getOwnPropertyNames(b);"
2838 " for (var i = 0; i < props.length; ++i) {"
2839 " var p = props[i];"
2840 " return arguments.callee(a[p], b[p]);"
2843 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2844 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2847 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2849 QFETCH(QString, expression);
2850 QFETCH(QString, compare);
2852 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2853 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2854 QVERIFY(object != 0);
2856 QJSValue value = engine.evaluate(expression);
2857 QVERIFY(!engine.hasUncaughtException());
2858 object->setProperty("expression", expression);
2859 object->setProperty("compare", compare);
2860 object->setProperty("pass", false);
2862 emit object->signalWithVariant(QVariant::fromValue(value));
2863 QVERIFY(object->property("pass").toBool());
2866 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2868 signalWithJSValueInVariant_data();
2871 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2873 QFETCH(QString, expression);
2874 QFETCH(QString, compare);
2876 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2877 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2878 QVERIFY(object != 0);
2881 QJSValue value = engine2.evaluate(expression);
2882 QVERIFY(!engine2.hasUncaughtException());
2883 object->setProperty("expression", expression);
2884 object->setProperty("compare", compare);
2885 object->setProperty("pass", false);
2887 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2888 emit object->signalWithVariant(QVariant::fromValue(value));
2889 QVERIFY(!object->property("pass").toBool());
2892 void tst_qdeclarativeecmascript::moduleApi_data()
2894 QTest::addColumn<QUrl>("testfile");
2895 QTest::addColumn<QString>("errorMessage");
2896 QTest::addColumn<QStringList>("warningMessages");
2897 QTest::addColumn<QStringList>("readProperties");
2898 QTest::addColumn<QVariantList>("readExpectedValues");
2899 QTest::addColumn<QStringList>("writeProperties");
2900 QTest::addColumn<QVariantList>("writeValues");
2901 QTest::addColumn<QStringList>("readBackProperties");
2902 QTest::addColumn<QVariantList>("readBackExpectedValues");
2904 QTest::newRow("qobject, register + read + method")
2905 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2908 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2909 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2910 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2916 QTest::newRow("script, register + read")
2917 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2920 << (QStringList() << "scriptTest")
2921 << (QVariantList() << 13)
2927 QTest::newRow("qobject, caching + read")
2928 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2931 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2932 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2938 QTest::newRow("script, caching + read")
2939 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2942 << (QStringList() << "scriptTest")
2943 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2949 QTest::newRow("qobject, writing + readonly constraints")
2950 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2952 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2953 << (QStringList() << "readOnlyProperty" << "writableProperty")
2954 << (QVariantList() << 20 << 50)
2955 << (QStringList() << "firstProperty" << "writableProperty")
2956 << (QVariantList() << 30 << 30)
2957 << (QStringList() << "readOnlyProperty" << "writableProperty")
2958 << (QVariantList() << 20 << 30);
2960 QTest::newRow("script, writing + readonly constraints")
2961 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2963 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2964 << (QStringList() << "readBack" << "unchanged")
2965 << (QVariantList() << 13 << 42)
2966 << (QStringList() << "firstProperty" << "secondProperty")
2967 << (QVariantList() << 30 << 30)
2968 << (QStringList() << "readBack" << "unchanged")
2969 << (QVariantList() << 30 << 42);
2971 QTest::newRow("qobject module API enum values in JS")
2972 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2975 << (QStringList() << "enumValue" << "enumMethod")
2976 << (QVariantList() << 42 << 30)
2982 QTest::newRow("qobject, invalid major version fail")
2983 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2984 << QString("QDeclarativeComponent: Component is not ready")
2993 QTest::newRow("qobject, invalid minor version fail")
2994 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2995 << QString("QDeclarativeComponent: Component is not ready")
3005 void tst_qdeclarativeecmascript::moduleApi()
3007 QFETCH(QUrl, testfile);
3008 QFETCH(QString, errorMessage);
3009 QFETCH(QStringList, warningMessages);
3010 QFETCH(QStringList, readProperties);
3011 QFETCH(QVariantList, readExpectedValues);
3012 QFETCH(QStringList, writeProperties);
3013 QFETCH(QVariantList, writeValues);
3014 QFETCH(QStringList, readBackProperties);
3015 QFETCH(QVariantList, readBackExpectedValues);
3017 QDeclarativeComponent component(&engine, testfile);
3019 if (!errorMessage.isEmpty())
3020 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3022 if (warningMessages.size())
3023 foreach (const QString &warning, warningMessages)
3024 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3026 QObject *object = component.create();
3027 if (!errorMessage.isEmpty()) {
3028 QVERIFY(object == 0);
3030 QVERIFY(object != 0);
3031 for (int i = 0; i < readProperties.size(); ++i)
3032 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3033 for (int i = 0; i < writeProperties.size(); ++i)
3034 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3035 for (int i = 0; i < readBackProperties.size(); ++i)
3036 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3041 void tst_qdeclarativeecmascript::importScripts_data()
3043 QTest::addColumn<QUrl>("testfile");
3044 QTest::addColumn<QString>("errorMessage");
3045 QTest::addColumn<QStringList>("warningMessages");
3046 QTest::addColumn<QStringList>("propertyNames");
3047 QTest::addColumn<QVariantList>("propertyValues");
3049 QTest::newRow("basic functionality")
3050 << TEST_FILE("jsimport/testImport.qml")
3053 << (QStringList() << QLatin1String("importedScriptStringValue")
3054 << QLatin1String("importedScriptFunctionValue")
3055 << QLatin1String("importedModuleAttachedPropertyValue")
3056 << QLatin1String("importedModuleEnumValue"))
3057 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3062 QTest::newRow("import scoping")
3063 << TEST_FILE("jsimport/testImportScoping.qml")
3066 << (QStringList() << QLatin1String("componentError"))
3067 << (QVariantList() << QVariant(5));
3069 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3070 << TEST_FILE("jsimportfail/failOne.qml")
3072 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3073 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3074 << (QVariantList() << QVariant(QString()));
3076 QTest::newRow("javascript imports in an import should be private to the import scope")
3077 << TEST_FILE("jsimportfail/failTwo.qml")
3079 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3080 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3081 << (QVariantList() << QVariant(QString()));
3083 QTest::newRow("module imports in an import should be private to the import scope")
3084 << TEST_FILE("jsimportfail/failThree.qml")
3086 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3087 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3088 << (QVariantList() << QVariant(false));
3090 QTest::newRow("typenames in an import should be private to the import scope")
3091 << TEST_FILE("jsimportfail/failFour.qml")
3093 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3094 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3095 << (QVariantList() << QVariant(0));
3097 QTest::newRow("import with imports has it's own activation scope")
3098 << TEST_FILE("jsimportfail/failFive.qml")
3100 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3101 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3102 << (QStringList() << QLatin1String("componentError"))
3103 << (QVariantList() << QVariant(0));
3105 QTest::newRow("import pragma library script")
3106 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3109 << (QStringList() << QLatin1String("testValue"))
3110 << (QVariantList() << QVariant(31));
3112 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3113 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3116 << (QStringList() << QLatin1String("testValue"))
3117 << (QVariantList() << QVariant(0));
3119 QTest::newRow("import pragma library script which has an import")
3120 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3123 << (QStringList() << QLatin1String("testValue"))
3124 << (QVariantList() << QVariant(55));
3126 QTest::newRow("import pragma library script which has a pragma library import")
3127 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3130 << (QStringList() << QLatin1String("testValue"))
3131 << (QVariantList() << QVariant(18));
3134 void tst_qdeclarativeecmascript::importScripts()
3136 QFETCH(QUrl, testfile);
3137 QFETCH(QString, errorMessage);
3138 QFETCH(QStringList, warningMessages);
3139 QFETCH(QStringList, propertyNames);
3140 QFETCH(QVariantList, propertyValues);
3142 QDeclarativeComponent component(&engine, testfile);
3144 if (!errorMessage.isEmpty())
3145 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3147 if (warningMessages.size())
3148 foreach (const QString &warning, warningMessages)
3149 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3151 QObject *object = component.create();
3152 if (!errorMessage.isEmpty()) {
3153 QVERIFY(object == 0);
3155 QVERIFY(object != 0);
3156 for (int i = 0; i < propertyNames.size(); ++i)
3157 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3162 void tst_qdeclarativeecmascript::scarceResources()
3164 QPixmap origPixmap(100, 100);
3165 origPixmap.fill(Qt::blue);
3167 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3168 ScarceResourceObject *eo = 0;
3169 QObject *object = 0;
3171 // in the following three cases, the instance created from the component
3172 // has a property which is a copy of the scarce resource; hence, the
3173 // resource should NOT be detached prior to deletion of the object instance,
3174 // unless the resource is destroyed explicitly.
3175 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3176 object = component.create();
3177 QVERIFY(object != 0);
3178 QVERIFY(object->property("scarceResourceCopy").isValid());
3179 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3180 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3181 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3182 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3185 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3186 object = componentTwo.create();
3187 QVERIFY(object != 0);
3188 QVERIFY(object->property("scarceResourceCopy").isValid());
3189 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3190 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3191 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3192 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3195 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3196 object = componentThree.create();
3197 QVERIFY(object != 0);
3198 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3199 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3200 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3201 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3204 // in the following three cases, no other copy should exist in memory,
3205 // and so it should be detached (unless explicitly preserved).
3206 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3207 object = componentFour.create();
3208 QVERIFY(object != 0);
3209 QVERIFY(object->property("scarceResourceTest").isValid());
3210 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3211 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3212 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3213 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3216 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3217 object = componentFive.create();
3218 QVERIFY(object != 0);
3219 QVERIFY(object->property("scarceResourceTest").isValid());
3220 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3221 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3222 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3223 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3226 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3227 object = componentSix.create();
3228 QVERIFY(object != 0);
3229 QVERIFY(object->property("scarceResourceTest").isValid());
3230 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3231 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3232 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3233 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3236 // test that scarce resources are handled correctly for imports
3237 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3238 object = componentSeven.create();
3239 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3240 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3243 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3244 object = componentEight.create();
3245 QVERIFY(object != 0);
3246 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3247 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3250 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3251 object = componentNine.create();
3252 QVERIFY(object != 0);
3253 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3254 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3255 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3256 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3257 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3258 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3261 // test that scarce resources are handled properly in signal invocation
3262 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3263 object = componentTen.create();
3264 QVERIFY(object != 0);
3265 QObject *srsc = object->findChild<QObject*>("srsc");
3267 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3268 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3269 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3270 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3271 QMetaObject::invokeMethod(srsc, "testSignal");
3272 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3273 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3274 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3275 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3276 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3277 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3278 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3279 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3280 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3281 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3284 // test that scarce resources are handled properly from js functions in qml files
3285 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3286 object = componentEleven.create();
3287 QVERIFY(object != 0);
3288 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3289 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3290 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3291 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3292 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3293 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3294 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3295 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3296 QMetaObject::invokeMethod(object, "releaseScarceResource");
3297 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3298 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3299 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3300 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3303 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3304 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3305 object = componentTwelve.create();
3306 QVERIFY(object != 0);
3307 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3308 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3309 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3310 QString srp_name = object->property("srp_name").toString();
3311 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3312 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3313 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3314 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3315 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3316 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3317 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3321 void tst_qdeclarativeecmascript::propertyChangeSlots()
3323 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3324 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3325 QObject *object = component.create();
3326 QVERIFY(object != 0);
3329 // ensure that invalid property names fail properly.
3330 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3331 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3332 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3333 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3334 object = e1.create();
3335 QVERIFY(object == 0);
3338 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3339 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3340 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3341 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3342 object = e2.create();
3343 QVERIFY(object == 0);
3346 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3347 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3348 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3349 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3350 object = e3.create();
3351 QVERIFY(object == 0);
3354 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3355 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3356 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3357 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3358 object = e4.create();
3359 QVERIFY(object == 0);
3363 void tst_qdeclarativeecmascript::propertyVar_data()
3365 QTest::addColumn<QUrl>("qmlFile");
3368 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3369 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3370 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3371 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3372 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3373 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3374 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3375 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3376 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3379 void tst_qdeclarativeecmascript::propertyVar()
3381 QFETCH(QUrl, qmlFile);
3383 QDeclarativeComponent component(&engine, qmlFile);
3384 QObject *object = component.create();
3385 QVERIFY(object != 0);
3387 QCOMPARE(object->property("test").toBool(), true);
3392 // Tests that we can write QVariant values to var properties from C++
3393 void tst_qdeclarativeecmascript::propertyVarCpp()
3395 QObject *object = 0;
3397 // ensure that writing to and reading from a var property from cpp works as required.
3398 // Literal values stored in var properties can be read and written as QVariants
3399 // of a specific type, whereas object values are read as QVariantMaps.
3400 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3401 object = component.create();
3402 QVERIFY(object != 0);
3403 // assign int to property var that currently has int assigned
3404 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3405 QCOMPARE(object->property("varBound"), QVariant(15));
3406 QCOMPARE(object->property("intBound"), QVariant(15));
3407 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3408 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3409 // assign string to property var that current has bool assigned
3410 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3411 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3412 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3413 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3414 // now enforce behaviour when accessing JavaScript objects from cpp.
3415 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3419 static void gc(QDeclarativeEngine &engine)
3421 engine.collectGarbage();
3422 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3425 void tst_qdeclarativeecmascript::propertyVarOwnership()
3427 // Referenced JS objects are not collected
3429 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3430 QObject *object = component.create();
3431 QVERIFY(object != 0);
3432 QCOMPARE(object->property("test").toBool(), false);
3433 QMetaObject::invokeMethod(object, "runTest");
3434 QCOMPARE(object->property("test").toBool(), true);
3437 // Referenced JS objects are not collected
3439 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3440 QObject *object = component.create();
3441 QVERIFY(object != 0);
3442 QCOMPARE(object->property("test").toBool(), false);
3443 QMetaObject::invokeMethod(object, "runTest");
3444 QCOMPARE(object->property("test").toBool(), true);
3447 // Qt objects are not collected until they've been dereferenced
3449 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3450 QObject *object = component.create();
3451 QVERIFY(object != 0);
3453 QCOMPARE(object->property("test2").toBool(), false);
3454 QCOMPARE(object->property("test2").toBool(), false);
3456 QMetaObject::invokeMethod(object, "runTest");
3457 QCOMPARE(object->property("test1").toBool(), true);
3459 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3460 QVERIFY(!referencedObject.isNull());
3462 QVERIFY(!referencedObject.isNull());
3464 QMetaObject::invokeMethod(object, "runTest2");
3465 QCOMPARE(object->property("test2").toBool(), true);
3467 QVERIFY(referencedObject.isNull());
3471 // Self reference does not prevent Qt object collection
3473 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3474 QObject *object = component.create();
3475 QVERIFY(object != 0);
3477 QCOMPARE(object->property("test").toBool(), true);
3479 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3480 QVERIFY(!referencedObject.isNull());
3482 QVERIFY(!referencedObject.isNull());
3484 QMetaObject::invokeMethod(object, "runTest");
3486 QVERIFY(referencedObject.isNull());
3492 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3494 // The childObject has a reference to a different QObject. We want to ensure
3495 // that the different item will not be cleaned up until required. IE, the childObject
3496 // has implicit ownership of the constructed QObject.
3497 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3498 QObject *object = component.create();
3499 QVERIFY(object != 0);
3500 QMetaObject::invokeMethod(object, "assignCircular");
3501 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3502 QObject *rootObject = object->property("vp").value<QObject*>();
3503 QVERIFY(rootObject != 0);
3504 QObject *childObject = rootObject->findChild<QObject*>("text");
3505 QVERIFY(childObject != 0);
3506 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3507 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3508 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3509 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3510 QVERIFY(!qobjectGuard.isNull());
3511 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3512 QVERIFY(!qobjectGuard.isNull());
3513 QMetaObject::invokeMethod(object, "deassignCircular");
3514 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3515 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3519 void tst_qdeclarativeecmascript::propertyVarReparent()
3521 // ensure that nothing breaks if we re-parent objects
3522 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3523 QObject *object = component.create();
3524 QVERIFY(object != 0);
3525 QMetaObject::invokeMethod(object, "assignVarProp");
3526 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3527 QObject *rect = object->property("vp").value<QObject*>();
3528 QObject *text = rect->findChild<QObject*>("textOne");
3529 QObject *text2 = rect->findChild<QObject*>("textTwo");
3530 QWeakPointer<QObject> rectGuard(rect);
3531 QWeakPointer<QObject> textGuard(text);
3532 QWeakPointer<QObject> text2Guard(text2);
3533 QVERIFY(!rectGuard.isNull());
3534 QVERIFY(!textGuard.isNull());
3535 QVERIFY(!text2Guard.isNull());
3536 QCOMPARE(text->property("textCanary").toInt(), 11);
3537 QCOMPARE(text2->property("textCanary").toInt(), 12);
3538 // now construct an image which we will reparent.
3539 QMetaObject::invokeMethod(text2, "constructQObject");
3540 QObject *image = text2->property("vp").value<QObject*>();
3541 QWeakPointer<QObject> imageGuard(image);
3542 QVERIFY(!imageGuard.isNull());
3543 QCOMPARE(image->property("imageCanary").toInt(), 13);
3544 // now reparent the "Image" object (currently, it has JS ownership)
3545 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3546 QMetaObject::invokeMethod(text2, "deassignVp");
3547 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3548 QCOMPARE(text->property("textCanary").toInt(), 11);
3549 QCOMPARE(text2->property("textCanary").toInt(), 22);
3550 QVERIFY(!imageGuard.isNull()); // should still be alive.
3551 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3552 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3553 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3554 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3558 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3560 // sometimes reparenting can cause problems
3561 // (eg, if the ctxt is collected, varproperties are no longer available)
3562 // this test ensures that no crash occurs in that situation.
3563 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3564 QObject *object = component.create();
3565 QVERIFY(object != 0);
3566 QMetaObject::invokeMethod(object, "assignVarProp");
3567 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3568 QObject *rect = object->property("vp").value<QObject*>();
3569 QObject *text = rect->findChild<QObject*>("textOne");
3570 QObject *text2 = rect->findChild<QObject*>("textTwo");
3571 QWeakPointer<QObject> rectGuard(rect);
3572 QWeakPointer<QObject> textGuard(text);
3573 QWeakPointer<QObject> text2Guard(text2);
3574 QVERIFY(!rectGuard.isNull());
3575 QVERIFY(!textGuard.isNull());
3576 QVERIFY(!text2Guard.isNull());
3577 QCOMPARE(text->property("textCanary").toInt(), 11);
3578 QCOMPARE(text2->property("textCanary").toInt(), 12);
3579 // now construct an image which we will reparent.
3580 QMetaObject::invokeMethod(text2, "constructQObject");
3581 QObject *image = text2->property("vp").value<QObject*>();
3582 QWeakPointer<QObject> imageGuard(image);
3583 QVERIFY(!imageGuard.isNull());
3584 QCOMPARE(image->property("imageCanary").toInt(), 13);
3585 // now reparent the "Image" object (currently, it has JS ownership)
3586 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3587 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3588 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3589 QVERIFY(!imageGuard.isNull()); // should still be alive.
3590 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3592 QVERIFY(imageGuard.isNull()); // should now be dead.
3595 void tst_qdeclarativeecmascript::propertyVarCircular()
3597 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3598 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3599 QObject *object = component.create();
3600 QVERIFY(object != 0);
3601 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3602 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3603 QCOMPARE(object->property("canaryInt"), QVariant(5));
3604 QVariant canaryResourceVariant = object->property("canaryResource");
3605 QVERIFY(canaryResourceVariant.isValid());
3606 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3607 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3608 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3609 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3610 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3611 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3612 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3613 QCOMPARE(object->property("canaryInt"), QVariant(2));
3614 QCOMPARE(object->property("canaryResource"), QVariant(1));
3615 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3619 void tst_qdeclarativeecmascript::propertyVarCircular2()
3621 // track deletion of JS-owned parent item with Cpp-owned child
3622 // where the child has a var property referencing its parent.
3623 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3624 QObject *object = component.create();
3625 QVERIFY(object != 0);
3626 QMetaObject::invokeMethod(object, "assignCircular");
3627 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3628 QObject *rootObject = object->property("vp").value<QObject*>();
3629 QVERIFY(rootObject != 0);
3630 QObject *childObject = rootObject->findChild<QObject*>("text");
3631 QVERIFY(childObject != 0);
3632 QWeakPointer<QObject> rootObjectTracker(rootObject);
3633 QVERIFY(!rootObjectTracker.isNull());
3634 QWeakPointer<QObject> childObjectTracker(childObject);
3635 QVERIFY(!childObjectTracker.isNull());
3637 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3638 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3639 QMetaObject::invokeMethod(object, "deassignCircular");
3640 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3641 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3642 QVERIFY(childObjectTracker.isNull()); // should have been collected
3646 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3648 *(int*)(parameter) += 1;
3649 qPersistentDispose(object);
3652 void tst_qdeclarativeecmascript::propertyVarInheritance()
3654 int propertyVarWeakRefCallbackCount = 0;
3656 // enforce behaviour regarding element inheritance - ensure handle disposal.
3657 // The particular component under test here has a chain of references.
3658 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3659 QObject *object = component.create();
3660 QVERIFY(object != 0);
3661 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3662 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3663 // we want to be able to track when the varProperties array of the last metaobject is disposed
3664 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3665 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*>();
3666 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3667 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3668 v8::Persistent<v8::Value> icoCanaryHandle;
3669 v8::Persistent<v8::Value> ccoCanaryHandle;
3672 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3673 // public function which can return us a handle to something in the varProperties array.
3674 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3675 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3676 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3677 // as the varproperties array of each vmemo still references the resource.
3678 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3679 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3681 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3683 // now we deassign the var prop, which should trigger collection of item subtrees.
3684 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3685 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3686 // ensure that there are only weak handles to the underlying varProperties array remaining.
3688 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3690 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3691 // to what remains are weak, all varProperties arrays must have been collected.
3694 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3696 int propertyVarWeakRefCallbackCount = 0;
3698 // The particular component under test here does NOT have a chain of references; the
3699 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3700 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3701 QObject *object = component.create();
3702 QVERIFY(object != 0);
3703 QMetaObject::invokeMethod(object, "assignCircular");
3704 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3705 QObject *rootObject = object->property("vp").value<QObject*>();
3706 QVERIFY(rootObject != 0);
3707 QObject *childObject = rootObject->findChild<QObject*>("text");
3708 QVERIFY(childObject != 0);
3709 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3710 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3711 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3714 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3715 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3716 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3718 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3719 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3721 QMetaObject::invokeMethod(object, "deassignCircular");
3722 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3723 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3727 // Ensure that QObject type conversion works on binding assignment
3728 void tst_qdeclarativeecmascript::elementAssign()
3730 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3732 QObject *object = component.create();
3733 QVERIFY(object != 0);
3735 QCOMPARE(object->property("test").toBool(), true);
3741 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3743 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3745 QObject *object = component.create();
3746 QVERIFY(object != 0);
3748 QCOMPARE(object->property("test").toBool(), true);
3754 void tst_qdeclarativeecmascript::objectConversion()
3756 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3758 QObject *object = component.create();
3759 QVERIFY(object != 0);
3761 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3762 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3769 void tst_qdeclarativeecmascript::booleanConversion()
3771 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3773 QObject *object = component.create();
3774 QVERIFY(object != 0);
3776 QCOMPARE(object->property("test_true1").toBool(), true);
3777 QCOMPARE(object->property("test_true2").toBool(), true);
3778 QCOMPARE(object->property("test_true3").toBool(), true);
3779 QCOMPARE(object->property("test_true4").toBool(), true);
3780 QCOMPARE(object->property("test_true5").toBool(), true);
3782 QCOMPARE(object->property("test_false1").toBool(), false);
3783 QCOMPARE(object->property("test_false2").toBool(), false);
3784 QCOMPARE(object->property("test_false3").toBool(), false);
3789 void tst_qdeclarativeecmascript::handleReferenceManagement()
3794 // Linear QObject reference
3795 QDeclarativeEngine hrmEngine;
3796 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3797 QObject *object = component.create();
3798 QVERIFY(object != 0);
3799 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3800 cro->setDtorCount(&dtorCount);
3801 QMetaObject::invokeMethod(object, "createReference");
3803 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3805 hrmEngine.collectGarbage();
3806 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3807 QCOMPARE(dtorCount, 3);
3812 // Circular QObject reference
3813 QDeclarativeEngine hrmEngine;
3814 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3815 QObject *object = component.create();
3816 QVERIFY(object != 0);
3817 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3818 cro->setDtorCount(&dtorCount);
3819 QMetaObject::invokeMethod(object, "circularReference");
3821 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3823 hrmEngine.collectGarbage();
3824 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3825 QCOMPARE(dtorCount, 3);
3830 // Linear handle reference
3831 QDeclarativeEngine hrmEngine;
3832 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3833 QObject *object = component.create();
3834 QVERIFY(object != 0);
3835 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3837 crh->setDtorCount(&dtorCount);
3838 QMetaObject::invokeMethod(object, "createReference");
3839 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3840 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3841 QVERIFY(first != 0);
3842 QVERIFY(second != 0);
3843 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3844 // now we have to reparent second and make second owned by JS.
3845 second->setParent(0);
3846 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3848 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3850 hrmEngine.collectGarbage();
3851 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3852 QCOMPARE(dtorCount, 3);
3857 // Circular handle reference
3858 QDeclarativeEngine hrmEngine;
3859 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3860 QObject *object = component.create();
3861 QVERIFY(object != 0);
3862 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3864 crh->setDtorCount(&dtorCount);
3865 QMetaObject::invokeMethod(object, "circularReference");
3866 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3867 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3868 QVERIFY(first != 0);
3869 QVERIFY(second != 0);
3870 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3871 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3872 // now we have to reparent and change ownership.
3873 first->setParent(0);
3874 second->setParent(0);
3875 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3876 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3878 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3880 hrmEngine.collectGarbage();
3881 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3882 QCOMPARE(dtorCount, 3);
3887 // multiple engine interaction - linear reference
3888 QDeclarativeEngine hrmEngine1;
3889 QDeclarativeEngine hrmEngine2;
3890 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3891 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3892 QObject *object1 = component1.create();
3893 QObject *object2 = component2.create();
3894 QVERIFY(object1 != 0);
3895 QVERIFY(object2 != 0);
3896 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3897 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3900 crh1->setDtorCount(&dtorCount);
3901 crh2->setDtorCount(&dtorCount);
3902 QMetaObject::invokeMethod(object1, "createReference");
3903 QMetaObject::invokeMethod(object2, "createReference");
3904 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3905 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3906 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3907 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3908 QVERIFY(first1 != 0);
3909 QVERIFY(second1 != 0);
3910 QVERIFY(first2 != 0);
3911 QVERIFY(second2 != 0);
3912 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3913 // now we have to reparent second2 and make second2 owned by JS.
3914 second2->setParent(0);
3915 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3917 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3918 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3921 hrmEngine1.collectGarbage();
3922 hrmEngine2.collectGarbage();
3923 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3924 QCOMPARE(dtorCount, 6);
3929 // multiple engine interaction - circular reference
3930 QDeclarativeEngine hrmEngine1;
3931 QDeclarativeEngine hrmEngine2;
3932 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3933 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3934 QObject *object1 = component1.create();
3935 QObject *object2 = component2.create();
3936 QVERIFY(object1 != 0);
3937 QVERIFY(object2 != 0);
3938 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3939 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3942 crh1->setDtorCount(&dtorCount);
3943 crh2->setDtorCount(&dtorCount);
3944 QMetaObject::invokeMethod(object1, "createReference");
3945 QMetaObject::invokeMethod(object2, "createReference");
3946 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3947 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3948 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3949 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3950 QVERIFY(first1 != 0);
3951 QVERIFY(second1 != 0);
3952 QVERIFY(first2 != 0);
3953 QVERIFY(second2 != 0);
3954 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3955 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3956 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3957 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3958 // now we have to reparent and change ownership to JS.
3959 first1->setParent(0);
3960 second1->setParent(0);
3961 first2->setParent(0);
3962 second2->setParent(0);
3963 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3964 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3965 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3966 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3968 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3969 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3972 hrmEngine1.collectGarbage();
3973 hrmEngine2.collectGarbage();
3974 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3975 QCOMPARE(dtorCount, 6);
3980 // multiple engine interaction - linear reference with engine deletion
3981 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3982 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3983 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3984 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3985 QObject *object1 = component1.create();
3986 QObject *object2 = component2.create();
3987 QVERIFY(object1 != 0);
3988 QVERIFY(object2 != 0);
3989 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3990 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3993 crh1->setDtorCount(&dtorCount);
3994 crh2->setDtorCount(&dtorCount);
3995 QMetaObject::invokeMethod(object1, "createReference");
3996 QMetaObject::invokeMethod(object2, "createReference");
3997 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3998 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3999 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4000 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4001 QVERIFY(first1 != 0);
4002 QVERIFY(second1 != 0);
4003 QVERIFY(first2 != 0);
4004 QVERIFY(second2 != 0);
4005 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4006 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4007 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4008 // now we have to reparent and change ownership to JS.
4009 first1->setParent(crh1);
4010 second1->setParent(0);
4011 first2->setParent(0);
4012 second2->setParent(0);
4013 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4014 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4015 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4017 QCOMPARE(dtorCount, 0);
4020 QCOMPARE(dtorCount, 0);
4023 hrmEngine1->collectGarbage();
4024 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4025 QCOMPARE(dtorCount, 6);
4030 void tst_qdeclarativeecmascript::stringArg()
4032 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4033 QObject *object = component.create();
4034 QVERIFY(object != 0);
4035 QMetaObject::invokeMethod(object, "success");
4036 QVERIFY(object->property("returnValue").toBool());
4038 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4039 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4040 QMetaObject::invokeMethod(object, "failure");
4041 QVERIFY(object->property("returnValue").toBool());
4046 void tst_qdeclarativeecmascript::readonlyDeclaration()
4048 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4050 QObject *object = component.create();
4051 QVERIFY(object != 0);
4053 QCOMPARE(object->property("test").toBool(), true);
4058 Q_DECLARE_METATYPE(QList<int>)
4059 Q_DECLARE_METATYPE(QList<qreal>)
4060 Q_DECLARE_METATYPE(QList<bool>)
4061 Q_DECLARE_METATYPE(QList<QString>)
4062 Q_DECLARE_METATYPE(QList<QUrl>)
4063 void tst_qdeclarativeecmascript::sequenceConversionRead()
4066 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4067 QDeclarativeComponent component(&engine, qmlFile);
4068 QObject *object = component.create();
4069 QVERIFY(object != 0);
4070 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4073 QMetaObject::invokeMethod(object, "readSequences");
4074 QList<int> intList; intList << 1 << 2 << 3 << 4;
4075 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4076 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4077 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4078 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4079 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4080 QList<bool> boolList; boolList << true << false << true << false;
4081 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4082 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4083 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4084 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4085 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4086 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4087 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4088 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4089 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4090 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4091 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4093 QMetaObject::invokeMethod(object, "readSequenceElements");
4094 QCOMPARE(object->property("intVal").toInt(), 2);
4095 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4096 QCOMPARE(object->property("boolVal").toBool(), false);
4097 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4098 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4099 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4101 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4102 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4104 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4105 QDeclarativeProperty seqProp(seq, "intListProperty");
4106 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4107 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4108 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4110 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4111 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4117 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4118 QDeclarativeComponent component(&engine, qmlFile);
4119 QObject *object = component.create();
4120 QVERIFY(object != 0);
4121 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4124 // we haven't registered QList<QPoint> as a sequence type.
4125 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4126 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4127 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4128 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4130 QMetaObject::invokeMethod(object, "performTest");
4132 // QList<QPoint> has not been registered as a sequence type.
4133 QCOMPARE(object->property("pointListLength").toInt(), 0);
4134 QVERIFY(!object->property("pointList").isValid());
4135 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4136 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4137 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4143 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4146 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4147 QDeclarativeComponent component(&engine, qmlFile);
4148 QObject *object = component.create();
4149 QVERIFY(object != 0);
4150 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4153 QMetaObject::invokeMethod(object, "writeSequences");
4154 QCOMPARE(object->property("success").toBool(), true);
4156 QMetaObject::invokeMethod(object, "writeSequenceElements");
4157 QCOMPARE(object->property("success").toBool(), true);
4159 QMetaObject::invokeMethod(object, "writeOtherElements");
4160 QCOMPARE(object->property("success").toBool(), true);
4162 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4163 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4169 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4170 QDeclarativeComponent component(&engine, qmlFile);
4171 QObject *object = component.create();
4172 QVERIFY(object != 0);
4173 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4176 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4177 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4178 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4180 QMetaObject::invokeMethod(object, "performTest");
4182 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4183 QCOMPARE(seq->pointListProperty(), pointList);
4189 void tst_qdeclarativeecmascript::sequenceConversionArray()
4191 // ensure that in JS the returned sequences act just like normal JS Arrays.
4192 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4193 QDeclarativeComponent component(&engine, qmlFile);
4194 QObject *object = component.create();
4195 QVERIFY(object != 0);
4196 //QMetaObject::invokeMethod(object, "indexedAccess");
4197 //QVERIFY(object->property("success").toBool());
4198 //QMetaObject::invokeMethod(object, "arrayOperations");
4199 //QVERIFY(object->property("success").toBool());
4200 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4201 QVERIFY(object->property("success").toBool());
4202 //QMetaObject::invokeMethod(object, "testReferenceDeletion");
4203 //QCOMPARE(object->property("referenceDeletion").toBool(), true);
4207 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4209 // ensure that sequence conversion operations work correctly in a worker thread
4210 // and that serialisation between the main and worker thread succeeds.
4211 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4212 QDeclarativeComponent component(&engine, qmlFile);
4213 QObject *object = component.create();
4214 QVERIFY(object != 0);
4216 QMetaObject::invokeMethod(object, "testIntSequence");
4217 QTRY_VERIFY(object->property("finished").toBool());
4218 QVERIFY(object->property("success").toBool());
4220 QMetaObject::invokeMethod(object, "testQrealSequence");
4221 QTRY_VERIFY(object->property("finished").toBool());
4222 QVERIFY(object->property("success").toBool());
4224 QMetaObject::invokeMethod(object, "testBoolSequence");
4225 QTRY_VERIFY(object->property("finished").toBool());
4226 QVERIFY(object->property("success").toBool());
4228 QMetaObject::invokeMethod(object, "testStringSequence");
4229 QTRY_VERIFY(object->property("finished").toBool());
4230 QVERIFY(object->property("success").toBool());
4232 QMetaObject::invokeMethod(object, "testQStringSequence");
4233 QTRY_VERIFY(object->property("finished").toBool());
4234 QVERIFY(object->property("success").toBool());
4236 QMetaObject::invokeMethod(object, "testUrlSequence");
4237 QTRY_VERIFY(object->property("finished").toBool());
4238 QVERIFY(object->property("success").toBool());
4243 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4246 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4247 QDeclarativeComponent component(&engine, qmlFile);
4248 QObject *object = component.create();
4249 QVERIFY(object != 0);
4250 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4251 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4252 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4253 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4254 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4259 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4260 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4261 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4262 QDeclarativeComponent component(&engine, qmlFile);
4263 QObject *object = component.create();
4264 QVERIFY(object != 0);
4269 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4271 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4272 QDeclarativeComponent component(&engine, qmlFile);
4273 QObject *object = component.create();
4274 QVERIFY(object != 0);
4275 QMetaObject::invokeMethod(object, "testCopySequences");
4276 QCOMPARE(object->property("success").toBool(), true);
4277 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4278 QCOMPARE(object->property("success").toBool(), true);
4279 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4280 QCOMPARE(object->property("success").toBool(), true);
4284 // Test that assigning a null object works
4285 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4286 void tst_qdeclarativeecmascript::nullObjectBinding()
4288 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4290 QObject *object = component.create();
4291 QVERIFY(object != 0);
4293 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4298 // Test that bindings don't evaluate once the engine has been destroyed
4299 void tst_qdeclarativeecmascript::deletedEngine()
4301 QDeclarativeEngine *engine = new QDeclarativeEngine;
4302 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4304 QObject *object = component.create();
4305 QVERIFY(object != 0);
4307 QCOMPARE(object->property("a").toInt(), 39);
4308 object->setProperty("b", QVariant(9));
4309 QCOMPARE(object->property("a").toInt(), 117);
4313 QCOMPARE(object->property("a").toInt(), 117);
4314 object->setProperty("b", QVariant(10));
4315 QCOMPARE(object->property("a").toInt(), 117);
4320 // Test the crashing part of QTBUG-9705
4321 void tst_qdeclarativeecmascript::libraryScriptAssert()
4323 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4325 QObject *object = component.create();
4326 QVERIFY(object != 0);
4331 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4333 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4335 QObject *object = component.create();
4336 QVERIFY(object != 0);
4338 QCOMPARE(object->property("test1").toInt(), 10);
4339 QCOMPARE(object->property("test2").toInt(), 11);
4341 object->setProperty("runTest", true);
4343 QCOMPARE(object->property("test1"), QVariant());
4344 QCOMPARE(object->property("test2"), QVariant());
4350 void tst_qdeclarativeecmascript::qtbug_9792()
4352 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4354 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4356 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4357 QVERIFY(object != 0);
4359 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4360 object->basicSignal();
4364 transientErrorsMsgCount = 0;
4365 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4367 object->basicSignal();
4369 qInstallMsgHandler(old);
4371 QCOMPARE(transientErrorsMsgCount, 0);
4376 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4377 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4379 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4381 QObject *o = component.create();
4384 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4385 QVERIFY(nested != 0);
4387 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4390 nested = qvariant_cast<QObject *>(o->property("object"));
4391 QVERIFY(nested == 0);
4393 // If the bug is present, the next line will crash
4397 // Test that we shut down without stupid warnings
4398 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4401 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4403 QObject *o = component.create();
4405 transientErrorsMsgCount = 0;
4406 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4410 qInstallMsgHandler(old);
4412 QCOMPARE(transientErrorsMsgCount, 0);
4417 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4419 QObject *o = component.create();
4421 transientErrorsMsgCount = 0;
4422 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4426 qInstallMsgHandler(old);
4428 QCOMPARE(transientErrorsMsgCount, 0);
4432 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4435 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4437 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4440 QVERIFY(o->objectProperty() != 0);
4442 o->setProperty("runTest", true);
4444 QVERIFY(o->objectProperty() == 0);
4450 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4452 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4455 QVERIFY(o->objectProperty() == 0);
4461 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4463 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4465 QString url = component.url().toString();
4466 QString warning = url + ":4: Unable to assign a function to a property.";
4467 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4469 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4472 QVERIFY(!o->property("a").isValid());
4477 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4479 QFETCH(QString, triggerProperty);
4481 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4482 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4484 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4486 QVERIFY(!o->property("a").isValid());
4488 o->setProperty("aNumber", QVariant(5));
4489 o->setProperty(triggerProperty.toUtf8().constData(), true);
4490 QCOMPARE(o->property("a"), QVariant(50));
4492 o->setProperty("aNumber", QVariant(10));
4493 QCOMPARE(o->property("a"), QVariant(100));
4498 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4500 QTest::addColumn<QString>("triggerProperty");
4502 QTest::newRow("assign to property") << "assignToProperty";
4503 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4505 QTest::newRow("assign to value type") << "assignToValueType";
4507 QTest::newRow("use 'this'") << "assignWithThis";
4508 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4511 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4513 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4514 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4516 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4518 QVERIFY(!o->property("a").isValid());
4520 o->setProperty("assignFuncWithoutReturn", true);
4521 QVERIFY(!o->property("a").isValid());
4523 QString url = component.url().toString();
4524 QString warning = url + ":67: Unable to assign QString to int";
4525 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4526 o->setProperty("assignWrongType", true);
4528 warning = url + ":71: Unable to assign QString to int";
4529 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4530 o->setProperty("assignWrongTypeToValueType", true);
4535 void tst_qdeclarativeecmascript::eval()
4537 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4539 QObject *o = component.create();
4542 QCOMPARE(o->property("test1").toBool(), true);
4543 QCOMPARE(o->property("test2").toBool(), true);
4544 QCOMPARE(o->property("test3").toBool(), true);
4545 QCOMPARE(o->property("test4").toBool(), true);
4546 QCOMPARE(o->property("test5").toBool(), true);
4551 void tst_qdeclarativeecmascript::function()
4553 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4555 QObject *o = component.create();
4558 QCOMPARE(o->property("test1").toBool(), true);
4559 QCOMPARE(o->property("test2").toBool(), true);
4560 QCOMPARE(o->property("test3").toBool(), true);
4565 // Test the "Qt.include" method
4566 void tst_qdeclarativeecmascript::include()
4568 // Non-library relative include
4570 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4571 QObject *o = component.create();
4574 QCOMPARE(o->property("test0").toInt(), 99);
4575 QCOMPARE(o->property("test1").toBool(), true);
4576 QCOMPARE(o->property("test2").toBool(), true);
4577 QCOMPARE(o->property("test2_1").toBool(), true);
4578 QCOMPARE(o->property("test3").toBool(), true);
4579 QCOMPARE(o->property("test3_1").toBool(), true);
4584 // Library relative include
4586 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4587 QObject *o = component.create();
4590 QCOMPARE(o->property("test0").toInt(), 99);
4591 QCOMPARE(o->property("test1").toBool(), true);
4592 QCOMPARE(o->property("test2").toBool(), true);
4593 QCOMPARE(o->property("test2_1").toBool(), true);
4594 QCOMPARE(o->property("test3").toBool(), true);
4595 QCOMPARE(o->property("test3_1").toBool(), true);
4602 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4603 QObject *o = component.create();
4606 QCOMPARE(o->property("test1").toBool(), true);
4607 QCOMPARE(o->property("test2").toBool(), true);
4608 QCOMPARE(o->property("test3").toBool(), true);
4609 QCOMPARE(o->property("test4").toBool(), true);
4610 QCOMPARE(o->property("test5").toBool(), true);
4611 QCOMPARE(o->property("test6").toBool(), true);
4616 // Including file with ".pragma library"
4618 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4619 QObject *o = component.create();
4621 QCOMPARE(o->property("test1").toInt(), 100);
4628 TestHTTPServer server(8111);
4629 QVERIFY(server.isValid());
4630 server.serveDirectory(TESTDATA(""));
4632 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4633 QObject *o = component.create();
4636 QTRY_VERIFY(o->property("done").toBool() == true);
4637 QTRY_VERIFY(o->property("done2").toBool() == true);
4639 QCOMPARE(o->property("test1").toBool(), true);
4640 QCOMPARE(o->property("test2").toBool(), true);
4641 QCOMPARE(o->property("test3").toBool(), true);
4642 QCOMPARE(o->property("test4").toBool(), true);
4643 QCOMPARE(o->property("test5").toBool(), true);
4645 QCOMPARE(o->property("test6").toBool(), true);
4646 QCOMPARE(o->property("test7").toBool(), true);
4647 QCOMPARE(o->property("test8").toBool(), true);
4648 QCOMPARE(o->property("test9").toBool(), true);
4649 QCOMPARE(o->property("test10").toBool(), true);
4656 TestHTTPServer server(8111);
4657 QVERIFY(server.isValid());
4658 server.serveDirectory(TESTDATA(""));
4660 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4661 QObject *o = component.create();
4664 QTRY_VERIFY(o->property("done").toBool() == true);
4666 QCOMPARE(o->property("test1").toBool(), true);
4667 QCOMPARE(o->property("test2").toBool(), true);
4668 QCOMPARE(o->property("test3").toBool(), true);
4674 void tst_qdeclarativeecmascript::signalHandlers()
4676 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4677 QObject *o = component.create();
4680 QVERIFY(o->property("count").toInt() == 0);
4681 QMetaObject::invokeMethod(o, "testSignalCall");
4682 QCOMPARE(o->property("count").toInt(), 1);
4684 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4685 QCOMPARE(o->property("count").toInt(), 1);
4686 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4688 QVERIFY(o->property("funcCount").toInt() == 0);
4689 QMetaObject::invokeMethod(o, "testSignalConnection");
4690 QCOMPARE(o->property("funcCount").toInt(), 1);
4692 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4693 QCOMPARE(o->property("funcCount").toInt(), 2);
4695 QMetaObject::invokeMethod(o, "testSignalDefined");
4696 QCOMPARE(o->property("definedResult").toBool(), true);
4698 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4699 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4704 void tst_qdeclarativeecmascript::qtbug_10696()
4706 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4707 QObject *o = component.create();
4712 void tst_qdeclarativeecmascript::qtbug_11606()
4714 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4715 QObject *o = component.create();
4717 QCOMPARE(o->property("test").toBool(), true);
4721 void tst_qdeclarativeecmascript::qtbug_11600()
4723 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4724 QObject *o = component.create();
4726 QCOMPARE(o->property("test").toBool(), true);
4730 // Reading and writing non-scriptable properties should fail
4731 void tst_qdeclarativeecmascript::nonscriptable()
4733 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4734 QObject *o = component.create();
4736 QCOMPARE(o->property("readOk").toBool(), true);
4737 QCOMPARE(o->property("writeOk").toBool(), true);
4741 // deleteLater() should not be callable from QML
4742 void tst_qdeclarativeecmascript::deleteLater()
4744 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4745 QObject *o = component.create();
4747 QCOMPARE(o->property("test").toBool(), true);
4751 void tst_qdeclarativeecmascript::in()
4753 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4754 QObject *o = component.create();
4756 QCOMPARE(o->property("test1").toBool(), true);
4757 QCOMPARE(o->property("test2").toBool(), true);
4761 void tst_qdeclarativeecmascript::typeOf()
4763 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4764 QObject *o = component.create();
4766 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4767 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4768 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4769 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4770 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4771 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4772 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4773 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4774 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4775 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4780 void tst_qdeclarativeecmascript::sharedAttachedObject()
4782 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4783 QObject *o = component.create();
4785 QCOMPARE(o->property("test1").toBool(), true);
4786 QCOMPARE(o->property("test2").toBool(), true);
4791 void tst_qdeclarativeecmascript::objectName()
4793 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4794 QObject *o = component.create();
4797 QCOMPARE(o->property("test1").toString(), QString("hello"));
4798 QCOMPARE(o->property("test2").toString(), QString("ell"));
4800 o->setObjectName("world");
4802 QCOMPARE(o->property("test1").toString(), QString("world"));
4803 QCOMPARE(o->property("test2").toString(), QString("orl"));
4808 void tst_qdeclarativeecmascript::writeRemovesBinding()
4810 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4811 QObject *o = component.create();
4814 QCOMPARE(o->property("test").toBool(), true);
4819 // Test bindings assigned to alias properties actually assign to the alias' target
4820 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4822 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4823 QObject *o = component.create();
4826 QCOMPARE(o->property("test").toBool(), true);
4831 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4832 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4835 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4836 QObject *o = component.create();
4839 QCOMPARE(o->property("test").toBool(), true);
4845 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4846 QObject *o = component.create();
4849 QCOMPARE(o->property("test").toBool(), true);
4855 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4856 QObject *o = component.create();
4859 QCOMPARE(o->property("test").toBool(), true);
4865 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4866 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4869 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4870 QObject *o = component.create();
4873 QCOMPARE(o->property("test").toBool(), true);
4879 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4880 QObject *o = component.create();
4883 QCOMPARE(o->property("test").toBool(), true);
4889 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4890 QObject *o = component.create();
4893 QCOMPARE(o->property("test").toBool(), true);
4899 // Allow an alais to a composite element
4901 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4903 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4905 QObject *object = component.create();
4906 QVERIFY(object != 0);
4911 void tst_qdeclarativeecmascript::revisionErrors()
4914 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4915 QString url = component.url().toString();
4917 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4918 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4919 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4921 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4922 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4923 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4924 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4925 QVERIFY(object != 0);
4929 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4930 QString url = component.url().toString();
4932 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4933 // method2, prop2 from MyRevisionedClass not available
4934 // method4, prop4 from MyRevisionedSubclass not available
4935 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4936 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4937 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4938 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4939 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4941 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4942 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4943 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4944 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4945 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4946 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4947 QVERIFY(object != 0);
4951 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4952 QString url = component.url().toString();
4954 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4955 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4956 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4957 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4958 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4959 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4960 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4961 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4962 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4963 QVERIFY(object != 0);
4968 void tst_qdeclarativeecmascript::revision()
4971 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4972 QString url = component.url().toString();
4974 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4975 QVERIFY(object != 0);
4979 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4980 QString url = component.url().toString();
4982 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4983 QVERIFY(object != 0);
4987 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4988 QString url = component.url().toString();
4990 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4991 QVERIFY(object != 0);
4994 // Test that non-root classes can resolve revisioned methods
4996 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4998 QObject *object = component.create();
4999 QVERIFY(object != 0);
5000 QCOMPARE(object->property("test").toReal(), 11.);
5005 void tst_qdeclarativeecmascript::realToInt()
5007 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5008 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5009 QVERIFY(object != 0);
5011 QMetaObject::invokeMethod(object, "test1");
5012 QCOMPARE(object->value(), int(4));
5013 QMetaObject::invokeMethod(object, "test2");
5014 QCOMPARE(object->value(), int(8));
5016 void tst_qdeclarativeecmascript::dynamicString()
5018 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5019 QObject *object = component.create();
5020 QVERIFY(object != 0);
5021 QCOMPARE(object->property("stringProperty").toString(),
5022 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5025 void tst_qdeclarativeecmascript::automaticSemicolon()
5027 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5028 QObject *object = component.create();
5029 QVERIFY(object != 0);
5032 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5033 void tst_qdeclarativeecmascript::doubleEvaluate()
5035 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5036 QObject *object = component.create();
5037 QVERIFY(object != 0);
5038 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5040 QCOMPARE(wc->count(), 1);
5042 wc->setProperty("x", 9);
5044 QCOMPARE(wc->count(), 2);
5049 void tst_qdeclarativeecmascript::forInLoop()
5051 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5052 QObject *object = component.create();
5053 QVERIFY(object != 0);
5055 QMetaObject::invokeMethod(object, "listProperty");
5057 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5058 QCOMPARE(r.size(), 3);
5059 QCOMPARE(r[0],QLatin1String("0=obj1"));
5060 QCOMPARE(r[1],QLatin1String("1=obj2"));
5061 QCOMPARE(r[2],QLatin1String("2=obj3"));
5063 //TODO: should test for in loop for other objects (such as QObjects) as well.
5068 QTEST_MAIN(tst_qdeclarativeecmascript)
5070 #include "tst_qdeclarativeecmascript.moc"