1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include <private/qv8gccallback_p.h>
53 #include <private/qdeclarativevmemetaobject_p.h>
54 #include <private/qv4compiler_p.h>
55 #include "testtypes.h"
56 #include "testhttpserver.h"
57 #include "../shared/util.h"
60 This test covers evaluation of ECMAScript expressions and bindings from within
61 QML. This does not include static QML language issues.
63 Static QML language issues are covered in qmllanguage
65 inline QUrl TEST_FILE(const QString &filename)
67 return QUrl::fromLocalFile(TESTDATA(filename));
70 inline QUrl TEST_FILE(const char *filename)
72 return TEST_FILE(QLatin1String(filename));
75 class tst_qdeclarativeecmascript : public QObject
79 tst_qdeclarativeecmascript() {}
83 void assignBasicTypes();
84 void idShortcutInvalidates();
85 void boolPropertiesEvaluateAsBool();
87 void signalAssignment();
89 void basicExpressions();
90 void basicExpressions_data();
91 void arrayExpressions();
92 void contextPropertiesTriggerReeval();
93 void objectPropertiesTriggerReeval();
94 void deferredProperties();
95 void deferredPropertiesErrors();
96 void extensionObjects();
97 void overrideExtensionProperties();
98 void attachedProperties();
100 void valueTypeFunctions();
101 void constantsOverrideBindings();
102 void outerBindingOverridesInnerBinding();
103 void aliasPropertyAndBinding();
104 void aliasPropertyReset();
105 void nonExistentAttachedObject();
108 void signalParameterTypes();
109 void objectsCompareAsEqual();
110 void dynamicCreation_data();
111 void dynamicCreation();
112 void dynamicDestruction();
113 void objectToString();
114 void objectHasOwnProperty();
115 void selfDeletingBinding();
116 void extendedObjectPropertyLookup();
118 void functionErrors();
119 void propertyAssignmentErrors();
120 void signalTriggeredBindings();
121 void listProperties();
122 void exceptionClearsOnReeval();
123 void exceptionSlotProducesWarning();
124 void exceptionBindingProducesWarning();
125 void transientErrors();
126 void shutdownErrors();
127 void compositePropertyType();
129 void undefinedResetsProperty();
130 void listToVariant();
131 void listAssignment();
132 void multiEngineObject();
133 void deletedObject();
134 void attachedPropertyScope();
135 void scriptConnect();
136 void scriptDisconnect();
138 void cppOwnershipReturnValue();
139 void ownershipCustomReturnValue();
140 void qlistqobjectMethods();
141 void strictlyEquals();
143 void numberAssignment();
144 void propertySplicing();
145 void signalWithUnknownTypes();
146 void signalWithJSValueInVariant_data();
147 void signalWithJSValueInVariant();
148 void signalWithJSValueInVariant_twoEngines_data();
149 void signalWithJSValueInVariant_twoEngines();
150 void moduleApi_data();
152 void importScripts_data();
153 void importScripts();
154 void scarceResources();
155 void propertyChangeSlots();
156 void propertyVar_data();
158 void propertyVarCpp();
159 void propertyVarOwnership();
160 void propertyVarImplicitOwnership();
161 void propertyVarReparent();
162 void propertyVarReparentNullContext();
163 void propertyVarCircular();
164 void propertyVarCircular2();
165 void propertyVarInheritance();
166 void propertyVarInheritance2();
167 void elementAssign();
168 void objectPassThroughSignals();
169 void objectConversion();
170 void booleanConversion();
171 void handleReferenceManagement();
173 void readonlyDeclaration();
174 void sequenceConversionRead();
175 void sequenceConversionWrite();
176 void sequenceConversionArray();
177 void sequenceConversionThreads();
178 void sequenceConversionBindings();
179 void sequenceConversionCopy();
184 void dynamicCreationCrash();
185 void dynamicCreationOwnership();
187 void nullObjectBinding();
188 void deletedEngine();
189 void libraryScriptAssert();
190 void variantsAssignedUndefined();
192 void qtcreatorbug_1289();
193 void noSpuriousWarningsAtShutdown();
194 void canAssignNullToQObject();
195 void functionAssignment_fromBinding();
196 void functionAssignment_fromJS();
197 void functionAssignment_fromJS_data();
198 void functionAssignmentfromJS_invalid();
204 void nonscriptable();
208 void sharedAttachedObject();
210 void writeRemovesBinding();
211 void aliasBindingsAssignCorrectly();
212 void aliasBindingsOverrideTarget();
213 void aliasWritesOverrideBindings();
214 void aliasToCompositeElement();
216 void dynamicString();
218 void signalHandlers();
219 void doubleEvaluate();
221 void nonNotifyable();
222 void deleteWhileBindingRunning();
223 void callQtInvokables();
224 void invokableObjectArg();
225 void invokableObjectRet();
228 void qtbug_22843_data();
230 void revisionErrors();
233 void automaticSemicolon();
234 void unaryExpression();
235 void switchStatement();
236 void withStatement();
240 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
241 QDeclarativeEngine engine;
244 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
246 void tst_qdeclarativeecmascript::assignBasicTypes()
249 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
250 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
251 QVERIFY(object != 0);
252 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
253 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
254 QCOMPARE(object->stringProperty(), QString("Hello World!"));
255 QCOMPARE(object->uintProperty(), uint(10));
256 QCOMPARE(object->intProperty(), -19);
257 QCOMPARE((float)object->realProperty(), float(23.2));
258 QCOMPARE((float)object->doubleProperty(), float(-19.75));
259 QCOMPARE((float)object->floatProperty(), float(8.5));
260 QCOMPARE(object->colorProperty(), QColor("red"));
261 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
262 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
263 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
264 QCOMPARE(object->pointProperty(), QPoint(99,13));
265 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
266 QCOMPARE(object->sizeProperty(), QSize(99, 13));
267 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
268 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
269 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
270 QCOMPARE(object->boolProperty(), true);
271 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
272 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
273 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
277 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
278 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
279 QVERIFY(object != 0);
280 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
281 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
282 QCOMPARE(object->stringProperty(), QString("Hello World!"));
283 QCOMPARE(object->uintProperty(), uint(10));
284 QCOMPARE(object->intProperty(), -19);
285 QCOMPARE((float)object->realProperty(), float(23.2));
286 QCOMPARE((float)object->doubleProperty(), float(-19.75));
287 QCOMPARE((float)object->floatProperty(), float(8.5));
288 QCOMPARE(object->colorProperty(), QColor("red"));
289 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
290 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
291 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
292 QCOMPARE(object->pointProperty(), QPoint(99,13));
293 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
294 QCOMPARE(object->sizeProperty(), QSize(99, 13));
295 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
296 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
297 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
298 QCOMPARE(object->boolProperty(), true);
299 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
300 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
301 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
306 void tst_qdeclarativeecmascript::idShortcutInvalidates()
309 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.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 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
320 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
321 QVERIFY(object != 0);
322 QVERIFY(object->objectProperty() != 0);
323 delete object->objectProperty();
324 QVERIFY(object->objectProperty() == 0);
329 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
332 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
333 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
334 QVERIFY(object != 0);
335 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
339 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
340 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
341 QVERIFY(object != 0);
342 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
347 void tst_qdeclarativeecmascript::signalAssignment()
350 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
351 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
352 QVERIFY(object != 0);
353 QCOMPARE(object->string(), QString());
354 emit object->basicSignal();
355 QCOMPARE(object->string(), QString("pass"));
360 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
361 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
362 QVERIFY(object != 0);
363 QCOMPARE(object->string(), QString());
364 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
365 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
370 void tst_qdeclarativeecmascript::methods()
373 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
374 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
375 QVERIFY(object != 0);
376 QCOMPARE(object->methodCalled(), false);
377 QCOMPARE(object->methodIntCalled(), false);
378 emit object->basicSignal();
379 QCOMPARE(object->methodCalled(), true);
380 QCOMPARE(object->methodIntCalled(), false);
385 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
386 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
387 QVERIFY(object != 0);
388 QCOMPARE(object->methodCalled(), false);
389 QCOMPARE(object->methodIntCalled(), false);
390 emit object->basicSignal();
391 QCOMPARE(object->methodCalled(), false);
392 QCOMPARE(object->methodIntCalled(), true);
397 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
398 QObject *object = component.create();
399 QVERIFY(object != 0);
400 QCOMPARE(object->property("test").toInt(), 19);
405 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
406 QObject *object = component.create();
407 QVERIFY(object != 0);
408 QCOMPARE(object->property("test").toInt(), 19);
409 QCOMPARE(object->property("test2").toInt(), 17);
410 QCOMPARE(object->property("test3").toInt(), 16);
415 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
416 QObject *object = component.create();
417 QVERIFY(object != 0);
418 QCOMPARE(object->property("test").toInt(), 9);
423 void tst_qdeclarativeecmascript::bindingLoop()
425 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
426 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
427 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
428 QObject *object = component.create();
429 QVERIFY(object != 0);
433 void tst_qdeclarativeecmascript::basicExpressions_data()
435 QTest::addColumn<QString>("expression");
436 QTest::addColumn<QVariant>("result");
437 QTest::addColumn<bool>("nest");
439 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
440 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
441 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
442 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
443 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
444 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
445 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
446 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
447 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
448 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
449 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
450 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
451 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
452 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
453 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
454 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
455 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
456 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
457 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
460 void tst_qdeclarativeecmascript::basicExpressions()
462 QFETCH(QString, expression);
463 QFETCH(QVariant, result);
469 MyDefaultObject1 default1;
470 MyDefaultObject3 default3;
471 object1.setStringProperty("Object1");
472 object2.setStringProperty("Object2");
473 object3.setStringProperty("Object3");
475 QDeclarativeContext context(engine.rootContext());
476 QDeclarativeContext nestedContext(&context);
478 context.setContextObject(&default1);
479 context.setContextProperty("a", QVariant(1944));
480 context.setContextProperty("b", QVariant("Milk"));
481 context.setContextProperty("object", &object1);
482 context.setContextProperty("objectOverride", &object2);
483 nestedContext.setContextObject(&default3);
484 nestedContext.setContextProperty("b", QVariant("Cow"));
485 nestedContext.setContextProperty("objectOverride", &object3);
486 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
488 MyExpression expr(nest?&nestedContext:&context, expression);
489 QCOMPARE(expr.evaluate(), result);
492 void tst_qdeclarativeecmascript::arrayExpressions()
498 QDeclarativeContext context(engine.rootContext());
499 context.setContextProperty("a", &obj1);
500 context.setContextProperty("b", &obj2);
501 context.setContextProperty("c", &obj3);
503 MyExpression expr(&context, "[a, b, c, 10]");
504 QVariant result = expr.evaluate();
505 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
506 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
507 QCOMPARE(list.count(), 4);
508 QCOMPARE(list.at(0), &obj1);
509 QCOMPARE(list.at(1), &obj2);
510 QCOMPARE(list.at(2), &obj3);
511 QCOMPARE(list.at(3), (QObject *)0);
514 // Tests that modifying a context property will reevaluate expressions
515 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
517 QDeclarativeContext context(engine.rootContext());
520 MyQmlObject *object3 = new MyQmlObject;
522 object1.setStringProperty("Hello");
523 object2.setStringProperty("World");
525 context.setContextProperty("testProp", QVariant(1));
526 context.setContextProperty("testObj", &object1);
527 context.setContextProperty("testObj2", object3);
530 MyExpression expr(&context, "testProp + 1");
531 QCOMPARE(expr.changed, false);
532 QCOMPARE(expr.evaluate(), QVariant(2));
534 context.setContextProperty("testProp", QVariant(2));
535 QCOMPARE(expr.changed, true);
536 QCOMPARE(expr.evaluate(), QVariant(3));
540 MyExpression expr(&context, "testProp + testProp + testProp");
541 QCOMPARE(expr.changed, false);
542 QCOMPARE(expr.evaluate(), QVariant(6));
544 context.setContextProperty("testProp", QVariant(4));
545 QCOMPARE(expr.changed, true);
546 QCOMPARE(expr.evaluate(), QVariant(12));
550 MyExpression expr(&context, "testObj.stringProperty");
551 QCOMPARE(expr.changed, false);
552 QCOMPARE(expr.evaluate(), QVariant("Hello"));
554 context.setContextProperty("testObj", &object2);
555 QCOMPARE(expr.changed, true);
556 QCOMPARE(expr.evaluate(), QVariant("World"));
560 MyExpression expr(&context, "testObj.stringProperty /**/");
561 QCOMPARE(expr.changed, false);
562 QCOMPARE(expr.evaluate(), QVariant("World"));
564 context.setContextProperty("testObj", &object1);
565 QCOMPARE(expr.changed, true);
566 QCOMPARE(expr.evaluate(), QVariant("Hello"));
570 MyExpression expr(&context, "testObj2");
571 QCOMPARE(expr.changed, false);
572 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
578 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
580 QDeclarativeContext context(engine.rootContext());
584 context.setContextProperty("testObj", &object1);
586 object1.setStringProperty(QLatin1String("Hello"));
587 object2.setStringProperty(QLatin1String("Dog"));
588 object3.setStringProperty(QLatin1String("Cat"));
591 MyExpression expr(&context, "testObj.stringProperty");
592 QCOMPARE(expr.changed, false);
593 QCOMPARE(expr.evaluate(), QVariant("Hello"));
595 object1.setStringProperty(QLatin1String("World"));
596 QCOMPARE(expr.changed, true);
597 QCOMPARE(expr.evaluate(), QVariant("World"));
601 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
602 QCOMPARE(expr.changed, false);
603 QCOMPARE(expr.evaluate(), QVariant());
605 object1.setObjectProperty(&object2);
606 QCOMPARE(expr.changed, true);
607 expr.changed = false;
608 QCOMPARE(expr.evaluate(), QVariant("Dog"));
610 object1.setObjectProperty(&object3);
611 QCOMPARE(expr.changed, true);
612 expr.changed = false;
613 QCOMPARE(expr.evaluate(), QVariant("Cat"));
615 object1.setObjectProperty(0);
616 QCOMPARE(expr.changed, true);
617 expr.changed = false;
618 QCOMPARE(expr.evaluate(), QVariant());
620 object1.setObjectProperty(&object3);
621 QCOMPARE(expr.changed, true);
622 expr.changed = false;
623 QCOMPARE(expr.evaluate(), QVariant("Cat"));
625 object3.setStringProperty("Donkey");
626 QCOMPARE(expr.changed, true);
627 expr.changed = false;
628 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
632 void tst_qdeclarativeecmascript::deferredProperties()
634 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
635 MyDeferredObject *object =
636 qobject_cast<MyDeferredObject *>(component.create());
637 QVERIFY(object != 0);
638 QCOMPARE(object->value(), 0);
639 QVERIFY(object->objectProperty() == 0);
640 QVERIFY(object->objectProperty2() != 0);
641 qmlExecuteDeferred(object);
642 QCOMPARE(object->value(), 10);
643 QVERIFY(object->objectProperty() != 0);
644 MyQmlObject *qmlObject =
645 qobject_cast<MyQmlObject *>(object->objectProperty());
646 QVERIFY(qmlObject != 0);
647 QCOMPARE(qmlObject->value(), 10);
648 object->setValue(19);
649 QCOMPARE(qmlObject->value(), 19);
654 // Check errors on deferred properties are correctly emitted
655 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
657 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
658 MyDeferredObject *object =
659 qobject_cast<MyDeferredObject *>(component.create());
660 QVERIFY(object != 0);
661 QCOMPARE(object->value(), 0);
662 QVERIFY(object->objectProperty() == 0);
663 QVERIFY(object->objectProperty2() == 0);
665 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
666 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
668 qmlExecuteDeferred(object);
673 void tst_qdeclarativeecmascript::extensionObjects()
675 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
676 MyExtendedObject *object =
677 qobject_cast<MyExtendedObject *>(component.create());
678 QVERIFY(object != 0);
679 QCOMPARE(object->baseProperty(), 13);
680 QCOMPARE(object->coreProperty(), 9);
681 object->setProperty("extendedProperty", QVariant(11));
682 object->setProperty("baseExtendedProperty", QVariant(92));
683 QCOMPARE(object->coreProperty(), 11);
684 QCOMPARE(object->baseProperty(), 92);
686 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
688 QCOMPARE(nested->baseProperty(), 13);
689 QCOMPARE(nested->coreProperty(), 9);
690 nested->setProperty("extendedProperty", QVariant(11));
691 nested->setProperty("baseExtendedProperty", QVariant(92));
692 QCOMPARE(nested->coreProperty(), 11);
693 QCOMPARE(nested->baseProperty(), 92);
698 void tst_qdeclarativeecmascript::overrideExtensionProperties()
700 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
701 OverrideDefaultPropertyObject *object =
702 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
703 QVERIFY(object != 0);
704 QVERIFY(object->secondProperty() != 0);
705 QVERIFY(object->firstProperty() == 0);
710 void tst_qdeclarativeecmascript::attachedProperties()
713 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
714 QObject *object = component.create();
715 QVERIFY(object != 0);
716 QCOMPARE(object->property("a").toInt(), 19);
717 QCOMPARE(object->property("b").toInt(), 19);
718 QCOMPARE(object->property("c").toInt(), 19);
719 QCOMPARE(object->property("d").toInt(), 19);
724 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
725 QObject *object = component.create();
726 QVERIFY(object != 0);
727 QCOMPARE(object->property("a").toInt(), 26);
728 QCOMPARE(object->property("b").toInt(), 26);
729 QCOMPARE(object->property("c").toInt(), 26);
730 QCOMPARE(object->property("d").toInt(), 26);
736 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
737 QObject *object = component.create();
738 QVERIFY(object != 0);
740 QMetaObject::invokeMethod(object, "writeValue2");
742 MyQmlAttachedObject *attached =
743 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
744 QVERIFY(attached != 0);
746 QCOMPARE(attached->value2(), 9);
751 void tst_qdeclarativeecmascript::enums()
755 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
756 QObject *object = component.create();
757 QVERIFY(object != 0);
759 QCOMPARE(object->property("a").toInt(), 0);
760 QCOMPARE(object->property("b").toInt(), 1);
761 QCOMPARE(object->property("c").toInt(), 2);
762 QCOMPARE(object->property("d").toInt(), 3);
763 QCOMPARE(object->property("e").toInt(), 0);
764 QCOMPARE(object->property("f").toInt(), 1);
765 QCOMPARE(object->property("g").toInt(), 2);
766 QCOMPARE(object->property("h").toInt(), 3);
767 QCOMPARE(object->property("i").toInt(), 19);
768 QCOMPARE(object->property("j").toInt(), 19);
772 // Non-existent enums
774 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
776 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
777 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
778 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
779 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
781 QObject *object = component.create();
782 QVERIFY(object != 0);
783 QCOMPARE(object->property("a").toInt(), 0);
784 QCOMPARE(object->property("b").toInt(), 0);
790 void tst_qdeclarativeecmascript::valueTypeFunctions()
792 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
793 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
795 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
796 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
802 Tests that writing a constant to a property with a binding on it disables the
805 void tst_qdeclarativeecmascript::constantsOverrideBindings()
809 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
810 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
811 QVERIFY(object != 0);
813 QCOMPARE(object->property("c2").toInt(), 0);
814 object->setProperty("c1", QVariant(9));
815 QCOMPARE(object->property("c2").toInt(), 9);
817 emit object->basicSignal();
819 QCOMPARE(object->property("c2").toInt(), 13);
820 object->setProperty("c1", QVariant(8));
821 QCOMPARE(object->property("c2").toInt(), 13);
826 // During construction
828 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
829 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
830 QVERIFY(object != 0);
832 QCOMPARE(object->property("c1").toInt(), 0);
833 QCOMPARE(object->property("c2").toInt(), 10);
834 object->setProperty("c1", QVariant(9));
835 QCOMPARE(object->property("c1").toInt(), 9);
836 QCOMPARE(object->property("c2").toInt(), 10);
844 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
845 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
846 QVERIFY(object != 0);
848 QCOMPARE(object->property("c2").toInt(), 0);
849 object->setProperty("c1", QVariant(9));
850 QCOMPARE(object->property("c2").toInt(), 9);
852 object->setProperty("c2", QVariant(13));
853 QCOMPARE(object->property("c2").toInt(), 13);
854 object->setProperty("c1", QVariant(7));
855 QCOMPARE(object->property("c1").toInt(), 7);
856 QCOMPARE(object->property("c2").toInt(), 13);
864 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
865 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
866 QVERIFY(object != 0);
868 QCOMPARE(object->property("c1").toInt(), 0);
869 QCOMPARE(object->property("c3").toInt(), 10);
870 object->setProperty("c1", QVariant(9));
871 QCOMPARE(object->property("c1").toInt(), 9);
872 QCOMPARE(object->property("c3").toInt(), 10);
879 Tests that assigning a binding to a property that already has a binding causes
880 the original binding to be disabled.
882 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
884 QDeclarativeComponent component(&engine,
885 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
886 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
887 QVERIFY(object != 0);
889 QCOMPARE(object->property("c1").toInt(), 0);
890 QCOMPARE(object->property("c2").toInt(), 0);
891 QCOMPARE(object->property("c3").toInt(), 0);
893 object->setProperty("c1", QVariant(9));
894 QCOMPARE(object->property("c1").toInt(), 9);
895 QCOMPARE(object->property("c2").toInt(), 0);
896 QCOMPARE(object->property("c3").toInt(), 0);
898 object->setProperty("c3", QVariant(8));
899 QCOMPARE(object->property("c1").toInt(), 9);
900 QCOMPARE(object->property("c2").toInt(), 8);
901 QCOMPARE(object->property("c3").toInt(), 8);
907 Access a non-existent attached object.
909 Tests for a regression where this used to crash.
911 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
913 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
915 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
916 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
918 QObject *object = component.create();
919 QVERIFY(object != 0);
924 void tst_qdeclarativeecmascript::scope()
927 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
928 QObject *object = component.create();
929 QVERIFY(object != 0);
931 QCOMPARE(object->property("test1").toInt(), 1);
932 QCOMPARE(object->property("test2").toInt(), 2);
933 QCOMPARE(object->property("test3").toString(), QString("1Test"));
934 QCOMPARE(object->property("test4").toString(), QString("2Test"));
935 QCOMPARE(object->property("test5").toInt(), 1);
936 QCOMPARE(object->property("test6").toInt(), 1);
937 QCOMPARE(object->property("test7").toInt(), 2);
938 QCOMPARE(object->property("test8").toInt(), 2);
939 QCOMPARE(object->property("test9").toInt(), 1);
940 QCOMPARE(object->property("test10").toInt(), 3);
946 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
947 QObject *object = component.create();
948 QVERIFY(object != 0);
950 QCOMPARE(object->property("test1").toInt(), 19);
951 QCOMPARE(object->property("test2").toInt(), 19);
952 QCOMPARE(object->property("test3").toInt(), 14);
953 QCOMPARE(object->property("test4").toInt(), 14);
954 QCOMPARE(object->property("test5").toInt(), 24);
955 QCOMPARE(object->property("test6").toInt(), 24);
961 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
962 QObject *object = component.create();
963 QVERIFY(object != 0);
965 QCOMPARE(object->property("test1").toBool(), true);
966 QCOMPARE(object->property("test2").toBool(), true);
967 QCOMPARE(object->property("test3").toBool(), true);
972 // Signal argument scope
974 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
975 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
976 QVERIFY(object != 0);
978 QCOMPARE(object->property("test").toInt(), 0);
979 QCOMPARE(object->property("test2").toString(), QString());
981 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
983 QCOMPARE(object->property("test").toInt(), 13);
984 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
990 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
991 QObject *object = component.create();
992 QVERIFY(object != 0);
994 QCOMPARE(object->property("test1").toBool(), true);
995 QCOMPARE(object->property("test2").toBool(), true);
1001 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
1002 QObject *object = component.create();
1003 QVERIFY(object != 0);
1005 QCOMPARE(object->property("test").toBool(), true);
1011 // In 4.7, non-library javascript files that had no imports shared the imports of their
1012 // importing context
1013 void tst_qdeclarativeecmascript::importScope()
1015 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1016 QObject *o = component.create();
1019 QCOMPARE(o->property("test").toInt(), 240);
1025 Tests that "any" type passes through a synthesized signal parameter. This
1026 is essentially a test of QDeclarativeMetaType::copy()
1028 void tst_qdeclarativeecmascript::signalParameterTypes()
1030 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1031 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1032 QVERIFY(object != 0);
1034 emit object->basicSignal();
1036 QCOMPARE(object->property("intProperty").toInt(), 10);
1037 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1038 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1039 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1040 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1041 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1047 Test that two JS objects for the same QObject compare as equal.
1049 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1051 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1052 QObject *object = component.create();
1053 QVERIFY(object != 0);
1055 QCOMPARE(object->property("test1").toBool(), true);
1056 QCOMPARE(object->property("test2").toBool(), true);
1057 QCOMPARE(object->property("test3").toBool(), true);
1058 QCOMPARE(object->property("test4").toBool(), true);
1059 QCOMPARE(object->property("test5").toBool(), true);
1065 Confirm bindings and alias properties can coexist.
1067 Tests for a regression where the binding would not reevaluate.
1069 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1071 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1072 QObject *object = component.create();
1073 QVERIFY(object != 0);
1075 QCOMPARE(object->property("c2").toInt(), 3);
1076 QCOMPARE(object->property("c3").toInt(), 3);
1078 object->setProperty("c2", QVariant(19));
1080 QCOMPARE(object->property("c2").toInt(), 19);
1081 QCOMPARE(object->property("c3").toInt(), 19);
1087 Ensure that we can write undefined value to an alias property,
1088 and that the aliased property is reset correctly if possible.
1090 void tst_qdeclarativeecmascript::aliasPropertyReset()
1092 QObject *object = 0;
1094 // test that a manual write (of undefined) to a resettable aliased property succeeds
1095 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1096 object = c1.create();
1097 QVERIFY(object != 0);
1098 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1099 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1100 QMetaObject::invokeMethod(object, "resetAliased");
1101 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1102 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1105 // test that a manual write (of undefined) to a resettable alias property succeeds
1106 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1107 object = c2.create();
1108 QVERIFY(object != 0);
1109 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1110 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1111 QMetaObject::invokeMethod(object, "resetAlias");
1112 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1113 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1116 // test that an alias to a bound property works correctly
1117 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1118 object = c3.create();
1119 QVERIFY(object != 0);
1120 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1121 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1122 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1123 QMetaObject::invokeMethod(object, "resetAlias");
1124 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1125 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1126 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1129 // test that a manual write (of undefined) to a resettable alias property
1130 // whose aliased property's object has been deleted, does not crash.
1131 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1132 object = c4.create();
1133 QVERIFY(object != 0);
1134 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1135 QObject *loader = object->findChild<QObject*>("loader");
1136 QVERIFY(loader != 0);
1138 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1139 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1140 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1141 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1142 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1145 // test that binding an alias property to an undefined value works correctly
1146 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1147 object = c5.create();
1148 QVERIFY(object != 0);
1149 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1152 // test that a manual write (of undefined) to a non-resettable property fails properly
1153 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1154 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1155 QDeclarativeComponent e1(&engine, url);
1156 object = e1.create();
1157 QVERIFY(object != 0);
1158 QCOMPARE(object->property("intAlias").value<int>(), 12);
1159 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1160 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1161 QMetaObject::invokeMethod(object, "resetAlias");
1162 QCOMPARE(object->property("intAlias").value<int>(), 12);
1163 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1167 void tst_qdeclarativeecmascript::dynamicCreation_data()
1169 QTest::addColumn<QString>("method");
1170 QTest::addColumn<QString>("createdName");
1172 QTest::newRow("One") << "createOne" << "objectOne";
1173 QTest::newRow("Two") << "createTwo" << "objectTwo";
1174 QTest::newRow("Three") << "createThree" << "objectThree";
1178 Test using createQmlObject to dynamically generate an item
1179 Also using createComponent is tested.
1181 void tst_qdeclarativeecmascript::dynamicCreation()
1183 QFETCH(QString, method);
1184 QFETCH(QString, createdName);
1186 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1187 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1188 QVERIFY(object != 0);
1190 QMetaObject::invokeMethod(object, method.toUtf8());
1191 QObject *created = object->objectProperty();
1193 QCOMPARE(created->objectName(), createdName);
1199 Tests the destroy function
1201 void tst_qdeclarativeecmascript::dynamicDestruction()
1204 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1205 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1206 QVERIFY(object != 0);
1207 QDeclarativeGuard<QObject> createdQmlObject = 0;
1209 QMetaObject::invokeMethod(object, "create");
1210 createdQmlObject = object->objectProperty();
1211 QVERIFY(createdQmlObject);
1212 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1214 QMetaObject::invokeMethod(object, "killOther");
1215 QVERIFY(createdQmlObject);
1216 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1217 QVERIFY(createdQmlObject);
1218 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1219 if (createdQmlObject) {
1221 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1224 QVERIFY(!createdQmlObject);
1226 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1227 QMetaObject::invokeMethod(object, "killMe");
1230 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1235 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1236 QObject *o = component.create();
1239 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1241 QMetaObject::invokeMethod(o, "create");
1243 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1245 QMetaObject::invokeMethod(o, "destroy");
1247 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1249 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1256 tests that id.toString() works
1258 void tst_qdeclarativeecmascript::objectToString()
1260 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1261 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1262 QVERIFY(object != 0);
1263 QMetaObject::invokeMethod(object, "testToString");
1264 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1265 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1271 tests that id.hasOwnProperty() works
1273 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1275 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1276 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1277 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1278 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1280 QDeclarativeComponent component(&engine, url);
1281 QObject *object = component.create();
1282 QVERIFY(object != 0);
1284 // test QObjects in QML
1285 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1286 QVERIFY(object->property("result").value<bool>() == true);
1287 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1288 QVERIFY(object->property("result").value<bool>() == false);
1290 // now test other types in QML
1291 QObject *child = object->findChild<QObject*>("typeObj");
1292 QVERIFY(child != 0);
1293 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1294 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1295 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1296 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1297 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1298 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1299 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1300 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1301 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1302 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1303 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1304 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1306 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1307 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1308 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1309 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1310 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1311 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1312 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1313 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1314 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1320 Tests bindings that indirectly cause their own deletion work.
1322 This test is best run under valgrind to ensure no invalid memory access occur.
1324 void tst_qdeclarativeecmascript::selfDeletingBinding()
1327 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1328 QObject *object = component.create();
1329 QVERIFY(object != 0);
1330 object->setProperty("triggerDelete", true);
1335 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1336 QObject *object = component.create();
1337 QVERIFY(object != 0);
1338 object->setProperty("triggerDelete", true);
1344 Test that extended object properties can be accessed.
1346 This test a regression where this used to crash. The issue was specificially
1347 for extended objects that did not include a synthesized meta object (so non-root
1348 and no synthesiszed properties).
1350 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1352 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1353 QObject *object = component.create();
1354 QVERIFY(object != 0);
1359 Test file/lineNumbers for binding/Script errors.
1361 void tst_qdeclarativeecmascript::scriptErrors()
1363 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1364 QString url = component.url().toString();
1366 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1367 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1368 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1369 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1370 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1371 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1372 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1373 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1375 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1376 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1377 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1378 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1379 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1380 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1381 QVERIFY(object != 0);
1383 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1384 emit object->basicSignal();
1386 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1387 emit object->anotherBasicSignal();
1389 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1390 emit object->thirdBasicSignal();
1396 Test file/lineNumbers for inline functions.
1398 void tst_qdeclarativeecmascript::functionErrors()
1400 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1401 QString url = component.url().toString();
1403 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1405 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1407 QObject *object = component.create();
1408 QVERIFY(object != 0);
1411 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1412 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1413 url = componentTwo.url().toString();
1414 object = componentTwo.create();
1415 QVERIFY(object != 0);
1417 QString srpname = object->property("srp_name").toString();
1419 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1420 QLatin1String(" is not a function");
1421 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1422 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1427 Test various errors that can occur when assigning a property from script
1429 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1431 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1433 QString url = component.url().toString();
1435 QObject *object = component.create();
1436 QVERIFY(object != 0);
1438 QCOMPARE(object->property("test1").toBool(), true);
1439 QCOMPARE(object->property("test2").toBool(), true);
1445 Test bindings still work when the reeval is triggered from within
1448 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1450 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1451 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1452 QVERIFY(object != 0);
1454 QCOMPARE(object->property("base").toReal(), 50.);
1455 QCOMPARE(object->property("test1").toReal(), 50.);
1456 QCOMPARE(object->property("test2").toReal(), 50.);
1458 object->basicSignal();
1460 QCOMPARE(object->property("base").toReal(), 200.);
1461 QCOMPARE(object->property("test1").toReal(), 200.);
1462 QCOMPARE(object->property("test2").toReal(), 200.);
1464 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1466 QCOMPARE(object->property("base").toReal(), 400.);
1467 QCOMPARE(object->property("test1").toReal(), 400.);
1468 QCOMPARE(object->property("test2").toReal(), 400.);
1474 Test that list properties can be iterated from ECMAScript
1476 void tst_qdeclarativeecmascript::listProperties()
1478 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1479 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1480 QVERIFY(object != 0);
1482 QCOMPARE(object->property("test1").toInt(), 21);
1483 QCOMPARE(object->property("test2").toInt(), 2);
1484 QCOMPARE(object->property("test3").toBool(), true);
1485 QCOMPARE(object->property("test4").toBool(), true);
1490 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1492 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1493 QString url = component.url().toString();
1495 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1497 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1498 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1499 QVERIFY(object != 0);
1501 QCOMPARE(object->property("test").toBool(), false);
1503 MyQmlObject object2;
1504 MyQmlObject object3;
1505 object2.setObjectProperty(&object3);
1506 object->setObjectProperty(&object2);
1508 QCOMPARE(object->property("test").toBool(), true);
1513 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1515 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1516 QString url = component.url().toString();
1518 QString warning = component.url().toString() + ":6: Error: JS exception";
1520 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1521 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1522 QVERIFY(object != 0);
1526 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1528 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1529 QString url = component.url().toString();
1531 QString warning = component.url().toString() + ":5: Error: JS exception";
1533 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1534 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1535 QVERIFY(object != 0);
1539 static int transientErrorsMsgCount = 0;
1540 static void transientErrorsMsgHandler(QtMsgType, const char *)
1542 ++transientErrorsMsgCount;
1545 // Check that transient binding errors are not displayed
1546 void tst_qdeclarativeecmascript::transientErrors()
1549 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1551 transientErrorsMsgCount = 0;
1552 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1554 QObject *object = component.create();
1555 QVERIFY(object != 0);
1557 qInstallMsgHandler(old);
1559 QCOMPARE(transientErrorsMsgCount, 0);
1564 // One binding erroring multiple times, but then resolving
1566 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1568 transientErrorsMsgCount = 0;
1569 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1571 QObject *object = component.create();
1572 QVERIFY(object != 0);
1574 qInstallMsgHandler(old);
1576 QCOMPARE(transientErrorsMsgCount, 0);
1582 // Check that errors during shutdown are minimized
1583 void tst_qdeclarativeecmascript::shutdownErrors()
1585 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1586 QObject *object = component.create();
1587 QVERIFY(object != 0);
1589 transientErrorsMsgCount = 0;
1590 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1594 qInstallMsgHandler(old);
1595 QCOMPARE(transientErrorsMsgCount, 0);
1598 void tst_qdeclarativeecmascript::compositePropertyType()
1600 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1602 QTest::ignoreMessage(QtDebugMsg, "hello world");
1603 QObject *object = qobject_cast<QObject *>(component.create());
1608 void tst_qdeclarativeecmascript::jsObject()
1610 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1611 QObject *object = component.create();
1612 QVERIFY(object != 0);
1614 QCOMPARE(object->property("test").toInt(), 92);
1619 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1622 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1623 QObject *object = component.create();
1624 QVERIFY(object != 0);
1626 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1628 object->setProperty("setUndefined", true);
1630 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1632 object->setProperty("setUndefined", false);
1634 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1639 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1640 QObject *object = component.create();
1641 QVERIFY(object != 0);
1643 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1645 QMetaObject::invokeMethod(object, "doReset");
1647 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1653 // Aliases to variant properties should work
1654 void tst_qdeclarativeecmascript::qtbug_22464()
1656 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1657 QObject *object = component.create();
1658 QVERIFY(object != 0);
1660 QCOMPARE(object->property("test").toBool(), true);
1665 void tst_qdeclarativeecmascript::qtbug_21580()
1667 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
1669 QObject *object = component.create();
1670 QVERIFY(object != 0);
1672 QCOMPARE(object->property("test").toBool(), true);
1678 void tst_qdeclarativeecmascript::bug1()
1680 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1681 QObject *object = component.create();
1682 QVERIFY(object != 0);
1684 QCOMPARE(object->property("test").toInt(), 14);
1686 object->setProperty("a", 11);
1688 QCOMPARE(object->property("test").toInt(), 3);
1690 object->setProperty("b", true);
1692 QCOMPARE(object->property("test").toInt(), 9);
1697 void tst_qdeclarativeecmascript::bug2()
1699 QDeclarativeComponent component(&engine);
1700 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1702 QObject *object = component.create();
1703 QVERIFY(object != 0);
1708 // Don't crash in createObject when the component has errors.
1709 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1711 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1712 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1713 QVERIFY(object != 0);
1715 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1716 QMetaObject::invokeMethod(object, "dontCrash");
1717 QObject *created = object->objectProperty();
1718 QVERIFY(created == 0);
1723 // ownership transferred to JS, ensure that GC runs the dtor
1724 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1727 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1729 // allow the engine to go out of scope too.
1731 QDeclarativeEngine dcoEngine;
1732 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1733 QObject *object = component.create();
1734 QVERIFY(object != 0);
1735 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1736 QVERIFY(mdcdo != 0);
1737 mdcdo->setDtorCount(&dtorCount);
1739 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1740 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1742 // we do this once manually, but it should be done automatically
1743 // when the engine goes out of scope (since it should gc in dtor)
1744 QMetaObject::invokeMethod(object, "performGc");
1747 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1753 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1754 QCOMPARE(dtorCount, expectedDtorCount);
1758 void tst_qdeclarativeecmascript::regExpBug()
1760 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1761 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1762 QVERIFY(object != 0);
1763 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1767 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1769 QString functionSource = QLatin1String("(function(object) { return ") +
1770 QLatin1String(source) + QLatin1String(" })");
1772 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1775 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1776 if (function.IsEmpty())
1778 v8::Handle<v8::Value> args[] = { o };
1779 function->Call(engine->global(), 1, args);
1780 return tc.HasCaught();
1783 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1784 const char *source, v8::Handle<v8::Value> result)
1786 QString functionSource = QLatin1String("(function(object) { return ") +
1787 QLatin1String(source) + QLatin1String(" })");
1789 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1792 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1793 if (function.IsEmpty())
1795 v8::Handle<v8::Value> args[] = { o };
1797 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1802 return value->StrictEquals(result);
1805 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1808 QString functionSource = QLatin1String("(function(object) { return ") +
1809 QLatin1String(source) + QLatin1String(" })");
1811 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1813 return v8::Handle<v8::Value>();
1814 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1815 if (function.IsEmpty())
1816 return v8::Handle<v8::Value>();
1817 v8::Handle<v8::Value> args[] = { o };
1819 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1822 return v8::Handle<v8::Value>();
1826 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1827 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1828 #define EVALUATE(source) evaluate(engine, object, source)
1830 void tst_qdeclarativeecmascript::callQtInvokables()
1832 MyInvokableObject o;
1834 QDeclarativeEngine qmlengine;
1835 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1837 QV8Engine *engine = ep->v8engine();
1839 v8::HandleScope handle_scope;
1840 v8::Context::Scope scope(engine->context());
1842 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1844 // Non-existent methods
1846 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1847 QCOMPARE(o.error(), false);
1848 QCOMPARE(o.invoked(), -1);
1849 QCOMPARE(o.actuals().count(), 0);
1852 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1853 QCOMPARE(o.error(), false);
1854 QCOMPARE(o.invoked(), -1);
1855 QCOMPARE(o.actuals().count(), 0);
1857 // Insufficient arguments
1859 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1860 QCOMPARE(o.error(), false);
1861 QCOMPARE(o.invoked(), -1);
1862 QCOMPARE(o.actuals().count(), 0);
1865 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1866 QCOMPARE(o.error(), false);
1867 QCOMPARE(o.invoked(), -1);
1868 QCOMPARE(o.actuals().count(), 0);
1870 // Excessive arguments
1872 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1873 QCOMPARE(o.error(), false);
1874 QCOMPARE(o.invoked(), 8);
1875 QCOMPARE(o.actuals().count(), 1);
1876 QCOMPARE(o.actuals().at(0), QVariant(10));
1879 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1880 QCOMPARE(o.error(), false);
1881 QCOMPARE(o.invoked(), 9);
1882 QCOMPARE(o.actuals().count(), 2);
1883 QCOMPARE(o.actuals().at(0), QVariant(10));
1884 QCOMPARE(o.actuals().at(1), QVariant(11));
1886 // Test return types
1888 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1889 QCOMPARE(o.error(), false);
1890 QCOMPARE(o.invoked(), 0);
1891 QCOMPARE(o.actuals().count(), 0);
1894 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1895 QCOMPARE(o.error(), false);
1896 QCOMPARE(o.invoked(), 1);
1897 QCOMPARE(o.actuals().count(), 0);
1900 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1901 QCOMPARE(o.error(), false);
1902 QCOMPARE(o.invoked(), 2);
1903 QCOMPARE(o.actuals().count(), 0);
1907 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1908 QVERIFY(!ret.IsEmpty());
1909 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1910 QCOMPARE(o.error(), false);
1911 QCOMPARE(o.invoked(), 3);
1912 QCOMPARE(o.actuals().count(), 0);
1917 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1918 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1919 QCOMPARE(o.error(), false);
1920 QCOMPARE(o.invoked(), 4);
1921 QCOMPARE(o.actuals().count(), 0);
1925 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1926 QCOMPARE(o.error(), false);
1927 QCOMPARE(o.invoked(), 5);
1928 QCOMPARE(o.actuals().count(), 0);
1932 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1933 QVERIFY(ret->IsString());
1934 QCOMPARE(engine->toString(ret), QString("Hello world"));
1935 QCOMPARE(o.error(), false);
1936 QCOMPARE(o.invoked(), 6);
1937 QCOMPARE(o.actuals().count(), 0);
1941 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1942 QCOMPARE(o.error(), false);
1943 QCOMPARE(o.invoked(), 7);
1944 QCOMPARE(o.actuals().count(), 0);
1948 QVERIFY(EVALUATE_VALUE("object.method_int(94)", 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(94));
1955 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1956 QCOMPARE(o.error(), false);
1957 QCOMPARE(o.invoked(), 8);
1958 QCOMPARE(o.actuals().count(), 1);
1959 QCOMPARE(o.actuals().at(0), QVariant(94));
1962 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1963 QCOMPARE(o.error(), false);
1964 QCOMPARE(o.invoked(), 8);
1965 QCOMPARE(o.actuals().count(), 1);
1966 QCOMPARE(o.actuals().at(0), QVariant(0));
1969 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1970 QCOMPARE(o.error(), false);
1971 QCOMPARE(o.invoked(), 8);
1972 QCOMPARE(o.actuals().count(), 1);
1973 QCOMPARE(o.actuals().at(0), QVariant(0));
1976 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1977 QCOMPARE(o.error(), false);
1978 QCOMPARE(o.invoked(), 8);
1979 QCOMPARE(o.actuals().count(), 1);
1980 QCOMPARE(o.actuals().at(0), QVariant(0));
1983 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1984 QCOMPARE(o.error(), false);
1985 QCOMPARE(o.invoked(), 8);
1986 QCOMPARE(o.actuals().count(), 1);
1987 QCOMPARE(o.actuals().at(0), QVariant(0));
1990 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1991 QCOMPARE(o.error(), false);
1992 QCOMPARE(o.invoked(), 9);
1993 QCOMPARE(o.actuals().count(), 2);
1994 QCOMPARE(o.actuals().at(0), QVariant(122));
1995 QCOMPARE(o.actuals().at(1), QVariant(9));
1998 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1999 QCOMPARE(o.error(), false);
2000 QCOMPARE(o.invoked(), 10);
2001 QCOMPARE(o.actuals().count(), 1);
2002 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2005 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2006 QCOMPARE(o.error(), false);
2007 QCOMPARE(o.invoked(), 10);
2008 QCOMPARE(o.actuals().count(), 1);
2009 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2012 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2013 QCOMPARE(o.error(), false);
2014 QCOMPARE(o.invoked(), 10);
2015 QCOMPARE(o.actuals().count(), 1);
2016 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2019 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2020 QCOMPARE(o.error(), false);
2021 QCOMPARE(o.invoked(), 10);
2022 QCOMPARE(o.actuals().count(), 1);
2023 QCOMPARE(o.actuals().at(0), QVariant(0));
2026 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2027 QCOMPARE(o.error(), false);
2028 QCOMPARE(o.invoked(), 10);
2029 QCOMPARE(o.actuals().count(), 1);
2030 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2033 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2034 QCOMPARE(o.error(), false);
2035 QCOMPARE(o.invoked(), 10);
2036 QCOMPARE(o.actuals().count(), 1);
2037 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2040 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2041 QCOMPARE(o.error(), false);
2042 QCOMPARE(o.invoked(), 11);
2043 QCOMPARE(o.actuals().count(), 1);
2044 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2047 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2048 QCOMPARE(o.error(), false);
2049 QCOMPARE(o.invoked(), 11);
2050 QCOMPARE(o.actuals().count(), 1);
2051 QCOMPARE(o.actuals().at(0), QVariant("19"));
2055 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2056 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2057 QCOMPARE(o.error(), false);
2058 QCOMPARE(o.invoked(), 11);
2059 QCOMPARE(o.actuals().count(), 1);
2060 QCOMPARE(o.actuals().at(0), QVariant(expected));
2064 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2065 QCOMPARE(o.error(), false);
2066 QCOMPARE(o.invoked(), 11);
2067 QCOMPARE(o.actuals().count(), 1);
2068 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2071 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2072 QCOMPARE(o.error(), false);
2073 QCOMPARE(o.invoked(), 11);
2074 QCOMPARE(o.actuals().count(), 1);
2075 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2078 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", 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()));
2085 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2086 QCOMPARE(o.error(), false);
2087 QCOMPARE(o.invoked(), 12);
2088 QCOMPARE(o.actuals().count(), 1);
2089 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2092 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2093 QCOMPARE(o.error(), false);
2094 QCOMPARE(o.invoked(), 12);
2095 QCOMPARE(o.actuals().count(), 1);
2096 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2099 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2100 QCOMPARE(o.error(), false);
2101 QCOMPARE(o.invoked(), 12);
2102 QCOMPARE(o.actuals().count(), 1);
2103 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2106 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2107 QCOMPARE(o.error(), false);
2108 QCOMPARE(o.invoked(), 12);
2109 QCOMPARE(o.actuals().count(), 1);
2110 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2113 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2114 QCOMPARE(o.error(), false);
2115 QCOMPARE(o.invoked(), 12);
2116 QCOMPARE(o.actuals().count(), 1);
2117 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2120 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2121 QCOMPARE(o.error(), false);
2122 QCOMPARE(o.invoked(), 13);
2123 QCOMPARE(o.actuals().count(), 1);
2124 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2127 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2128 QCOMPARE(o.error(), false);
2129 QCOMPARE(o.invoked(), 13);
2130 QCOMPARE(o.actuals().count(), 1);
2131 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2134 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2135 QCOMPARE(o.error(), false);
2136 QCOMPARE(o.invoked(), 13);
2137 QCOMPARE(o.actuals().count(), 1);
2138 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2141 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2142 QCOMPARE(o.error(), false);
2143 QCOMPARE(o.invoked(), 13);
2144 QCOMPARE(o.actuals().count(), 1);
2145 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2148 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2149 QCOMPARE(o.error(), false);
2150 QCOMPARE(o.invoked(), 13);
2151 QCOMPARE(o.actuals().count(), 1);
2152 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2155 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2156 QCOMPARE(o.error(), false);
2157 QCOMPARE(o.invoked(), 14);
2158 QCOMPARE(o.actuals().count(), 1);
2159 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2162 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2163 QCOMPARE(o.error(), false);
2164 QCOMPARE(o.invoked(), 14);
2165 QCOMPARE(o.actuals().count(), 1);
2166 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2169 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2170 QCOMPARE(o.error(), false);
2171 QCOMPARE(o.invoked(), 14);
2172 QCOMPARE(o.actuals().count(), 1);
2173 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2176 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2177 QCOMPARE(o.error(), false);
2178 QCOMPARE(o.invoked(), 14);
2179 QCOMPARE(o.actuals().count(), 1);
2180 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2183 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2184 QCOMPARE(o.error(), false);
2185 QCOMPARE(o.invoked(), 15);
2186 QCOMPARE(o.actuals().count(), 2);
2187 QCOMPARE(o.actuals().at(0), QVariant(4));
2188 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2191 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2192 QCOMPARE(o.error(), false);
2193 QCOMPARE(o.invoked(), 15);
2194 QCOMPARE(o.actuals().count(), 2);
2195 QCOMPARE(o.actuals().at(0), QVariant(8));
2196 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2199 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2200 QCOMPARE(o.error(), false);
2201 QCOMPARE(o.invoked(), 15);
2202 QCOMPARE(o.actuals().count(), 2);
2203 QCOMPARE(o.actuals().at(0), QVariant(3));
2204 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2207 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2208 QCOMPARE(o.error(), false);
2209 QCOMPARE(o.invoked(), 15);
2210 QCOMPARE(o.actuals().count(), 2);
2211 QCOMPARE(o.actuals().at(0), QVariant(44));
2212 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2215 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2216 QCOMPARE(o.error(), false);
2217 QCOMPARE(o.invoked(), -1);
2218 QCOMPARE(o.actuals().count(), 0);
2221 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2222 QCOMPARE(o.error(), false);
2223 QCOMPARE(o.invoked(), 16);
2224 QCOMPARE(o.actuals().count(), 1);
2225 QCOMPARE(o.actuals().at(0), QVariant(10));
2228 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2229 QCOMPARE(o.error(), false);
2230 QCOMPARE(o.invoked(), 17);
2231 QCOMPARE(o.actuals().count(), 2);
2232 QCOMPARE(o.actuals().at(0), QVariant(10));
2233 QCOMPARE(o.actuals().at(1), QVariant(11));
2236 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2237 QCOMPARE(o.error(), false);
2238 QCOMPARE(o.invoked(), 18);
2239 QCOMPARE(o.actuals().count(), 1);
2240 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2243 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2244 QCOMPARE(o.error(), false);
2245 QCOMPARE(o.invoked(), 19);
2246 QCOMPARE(o.actuals().count(), 1);
2247 QCOMPARE(o.actuals().at(0), QVariant(9));
2250 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2251 QCOMPARE(o.error(), false);
2252 QCOMPARE(o.invoked(), 20);
2253 QCOMPARE(o.actuals().count(), 2);
2254 QCOMPARE(o.actuals().at(0), QVariant(10));
2255 QCOMPARE(o.actuals().at(1), QVariant(19));
2258 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2259 QCOMPARE(o.error(), false);
2260 QCOMPARE(o.invoked(), 20);
2261 QCOMPARE(o.actuals().count(), 2);
2262 QCOMPARE(o.actuals().at(0), QVariant(10));
2263 QCOMPARE(o.actuals().at(1), QVariant(13));
2266 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2267 QCOMPARE(o.error(), false);
2268 QCOMPARE(o.invoked(), -3);
2269 QCOMPARE(o.actuals().count(), 1);
2270 QCOMPARE(o.actuals().at(0), QVariant(9));
2273 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2274 QCOMPARE(o.error(), false);
2275 QCOMPARE(o.invoked(), 21);
2276 QCOMPARE(o.actuals().count(), 2);
2277 QCOMPARE(o.actuals().at(0), QVariant(9));
2278 QCOMPARE(o.actuals().at(1), QVariant());
2281 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2282 QCOMPARE(o.error(), false);
2283 QCOMPARE(o.invoked(), 21);
2284 QCOMPARE(o.actuals().count(), 2);
2285 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2286 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2289 // QTBUG-13047 (check that you can pass registered object types as args)
2290 void tst_qdeclarativeecmascript::invokableObjectArg()
2292 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2294 QObject *o = component.create();
2296 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2298 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2303 // QTBUG-13047 (check that you can return registered object types from methods)
2304 void tst_qdeclarativeecmascript::invokableObjectRet()
2306 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2308 QObject *o = component.create();
2310 QCOMPARE(o->property("test").toBool(), true);
2315 void tst_qdeclarativeecmascript::listToVariant()
2317 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2319 MyQmlContainer container;
2321 QDeclarativeContext context(engine.rootContext());
2322 context.setContextObject(&container);
2324 QObject *object = component.create(&context);
2325 QVERIFY(object != 0);
2327 QVariant v = object->property("test");
2328 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2329 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2335 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2336 void tst_qdeclarativeecmascript::listAssignment()
2338 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2339 QObject *obj = component.create();
2340 QCOMPARE(obj->property("list1length").toInt(), 2);
2341 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2342 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2343 QCOMPARE(list1.count(&list1), list2.count(&list2));
2344 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2345 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2350 void tst_qdeclarativeecmascript::multiEngineObject()
2353 obj.setStringProperty("Howdy planet");
2355 QDeclarativeEngine e1;
2356 e1.rootContext()->setContextProperty("thing", &obj);
2357 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2359 QDeclarativeEngine e2;
2360 e2.rootContext()->setContextProperty("thing", &obj);
2361 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2363 QObject *o1 = c1.create();
2364 QObject *o2 = c2.create();
2366 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2367 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2373 // Test that references to QObjects are cleanup when the object is destroyed
2374 void tst_qdeclarativeecmascript::deletedObject()
2376 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2378 QObject *object = component.create();
2380 QCOMPARE(object->property("test1").toBool(), true);
2381 QCOMPARE(object->property("test2").toBool(), true);
2382 QCOMPARE(object->property("test3").toBool(), true);
2383 QCOMPARE(object->property("test4").toBool(), true);
2388 void tst_qdeclarativeecmascript::attachedPropertyScope()
2390 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2392 QObject *object = component.create();
2393 QVERIFY(object != 0);
2395 MyQmlAttachedObject *attached =
2396 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2397 QVERIFY(attached != 0);
2399 QCOMPARE(object->property("value2").toInt(), 0);
2401 attached->emitMySignal();
2403 QCOMPARE(object->property("value2").toInt(), 9);
2408 void tst_qdeclarativeecmascript::scriptConnect()
2411 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2413 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2414 QVERIFY(object != 0);
2416 QCOMPARE(object->property("test").toBool(), false);
2417 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2418 QCOMPARE(object->property("test").toBool(), true);
2424 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2426 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2427 QVERIFY(object != 0);
2429 QCOMPARE(object->property("test").toBool(), false);
2430 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2431 QCOMPARE(object->property("test").toBool(), true);
2437 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2439 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2440 QVERIFY(object != 0);
2442 QCOMPARE(object->property("test").toBool(), false);
2443 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2444 QCOMPARE(object->property("test").toBool(), true);
2450 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2452 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2453 QVERIFY(object != 0);
2455 QCOMPARE(object->methodCalled(), false);
2456 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2457 QCOMPARE(object->methodCalled(), true);
2463 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2465 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2466 QVERIFY(object != 0);
2468 QCOMPARE(object->methodCalled(), false);
2469 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2470 QCOMPARE(object->methodCalled(), true);
2476 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.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(), 2);
2489 void tst_qdeclarativeecmascript::scriptDisconnect()
2492 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2494 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2495 QVERIFY(object != 0);
2497 QCOMPARE(object->property("test").toInt(), 0);
2498 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2499 QCOMPARE(object->property("test").toInt(), 1);
2500 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2501 QCOMPARE(object->property("test").toInt(), 2);
2502 emit object->basicSignal();
2503 QCOMPARE(object->property("test").toInt(), 2);
2504 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2505 QCOMPARE(object->property("test").toInt(), 2);
2511 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2513 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2514 QVERIFY(object != 0);
2516 QCOMPARE(object->property("test").toInt(), 0);
2517 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2518 QCOMPARE(object->property("test").toInt(), 1);
2519 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2520 QCOMPARE(object->property("test").toInt(), 2);
2521 emit object->basicSignal();
2522 QCOMPARE(object->property("test").toInt(), 2);
2523 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2524 QCOMPARE(object->property("test").toInt(), 2);
2530 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2532 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2533 QVERIFY(object != 0);
2535 QCOMPARE(object->property("test").toInt(), 0);
2536 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2537 QCOMPARE(object->property("test").toInt(), 1);
2538 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2539 QCOMPARE(object->property("test").toInt(), 2);
2540 emit object->basicSignal();
2541 QCOMPARE(object->property("test").toInt(), 2);
2542 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2543 QCOMPARE(object->property("test").toInt(), 3);
2548 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2550 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2551 QVERIFY(object != 0);
2553 QCOMPARE(object->property("test").toInt(), 0);
2554 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2555 QCOMPARE(object->property("test").toInt(), 1);
2556 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2557 QCOMPARE(object->property("test").toInt(), 2);
2558 emit object->basicSignal();
2559 QCOMPARE(object->property("test").toInt(), 2);
2560 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2561 QCOMPARE(object->property("test").toInt(), 3);
2567 class OwnershipObject : public QObject
2571 OwnershipObject() { object = new QObject; }
2573 QPointer<QObject> object;
2576 QObject *getObject() { return object; }
2579 void tst_qdeclarativeecmascript::ownership()
2581 OwnershipObject own;
2582 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2583 context->setContextObject(&own);
2586 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2588 QVERIFY(own.object != 0);
2590 QObject *object = component.create(context);
2592 engine.collectGarbage();
2594 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2596 QVERIFY(own.object == 0);
2601 own.object = new QObject(&own);
2604 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2606 QVERIFY(own.object != 0);
2608 QObject *object = component.create(context);
2610 engine.collectGarbage();
2612 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2614 QVERIFY(own.object != 0);
2622 class CppOwnershipReturnValue : public QObject
2626 CppOwnershipReturnValue() : value(0) {}
2627 ~CppOwnershipReturnValue() { delete value; }
2629 Q_INVOKABLE QObject *create() {
2630 value = new QObject;
2631 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2635 Q_INVOKABLE MyQmlObject *createQmlObject() {
2636 MyQmlObject *rv = new MyQmlObject;
2641 QPointer<QObject> value;
2645 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2646 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2648 CppOwnershipReturnValue source;
2651 QDeclarativeEngine engine;
2652 engine.rootContext()->setContextProperty("source", &source);
2654 QVERIFY(source.value == 0);
2656 QDeclarativeComponent component(&engine);
2657 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2659 QObject *object = component.create();
2661 QVERIFY(object != 0);
2662 QVERIFY(source.value != 0);
2667 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2669 QVERIFY(source.value != 0);
2673 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2675 CppOwnershipReturnValue source;
2678 QDeclarativeEngine engine;
2679 engine.rootContext()->setContextProperty("source", &source);
2681 QVERIFY(source.value == 0);
2683 QDeclarativeComponent component(&engine);
2684 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2686 QObject *object = component.create();
2688 QVERIFY(object != 0);
2689 QVERIFY(source.value != 0);
2694 engine.collectGarbage();
2695 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2697 QVERIFY(source.value == 0);
2700 class QListQObjectMethodsObject : public QObject
2704 QListQObjectMethodsObject() {
2705 m_objects.append(new MyQmlObject());
2706 m_objects.append(new MyQmlObject());
2709 ~QListQObjectMethodsObject() {
2710 qDeleteAll(m_objects);
2714 QList<QObject *> getObjects() { return m_objects; }
2717 QList<QObject *> m_objects;
2720 // Tests that returning a QList<QObject*> from a method works
2721 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2723 QListQObjectMethodsObject obj;
2724 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2725 context->setContextObject(&obj);
2727 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2729 QObject *object = component.create(context);
2731 QCOMPARE(object->property("test").toInt(), 2);
2732 QCOMPARE(object->property("test2").toBool(), true);
2739 void tst_qdeclarativeecmascript::strictlyEquals()
2741 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2743 QObject *object = component.create();
2744 QVERIFY(object != 0);
2746 QCOMPARE(object->property("test1").toBool(), true);
2747 QCOMPARE(object->property("test2").toBool(), true);
2748 QCOMPARE(object->property("test3").toBool(), true);
2749 QCOMPARE(object->property("test4").toBool(), true);
2750 QCOMPARE(object->property("test5").toBool(), true);
2751 QCOMPARE(object->property("test6").toBool(), true);
2752 QCOMPARE(object->property("test7").toBool(), true);
2753 QCOMPARE(object->property("test8").toBool(), true);
2758 void tst_qdeclarativeecmascript::compiled()
2760 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2762 QObject *object = component.create();
2763 QVERIFY(object != 0);
2765 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2766 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2767 QCOMPARE(object->property("test3").toBool(), true);
2768 QCOMPARE(object->property("test4").toBool(), false);
2769 QCOMPARE(object->property("test5").toBool(), false);
2770 QCOMPARE(object->property("test6").toBool(), true);
2772 QCOMPARE(object->property("test7").toInt(), 185);
2773 QCOMPARE(object->property("test8").toInt(), 167);
2774 QCOMPARE(object->property("test9").toBool(), true);
2775 QCOMPARE(object->property("test10").toBool(), false);
2776 QCOMPARE(object->property("test11").toBool(), false);
2777 QCOMPARE(object->property("test12").toBool(), true);
2779 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2780 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2781 QCOMPARE(object->property("test15").toBool(), false);
2782 QCOMPARE(object->property("test16").toBool(), true);
2784 QCOMPARE(object->property("test17").toInt(), 5);
2785 QCOMPARE(object->property("test18").toReal(), qreal(176));
2786 QCOMPARE(object->property("test19").toInt(), 7);
2787 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2788 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2789 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2790 QCOMPARE(object->property("test23").toBool(), true);
2791 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2792 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2797 // Test that numbers assigned in bindings as strings work consistently
2798 void tst_qdeclarativeecmascript::numberAssignment()
2800 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2802 QObject *object = component.create();
2803 QVERIFY(object != 0);
2805 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2806 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2807 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2808 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2809 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2811 QCOMPARE(object->property("test5"), QVariant((int)7));
2812 QCOMPARE(object->property("test6"), QVariant((int)7));
2813 QCOMPARE(object->property("test7"), QVariant((int)6));
2814 QCOMPARE(object->property("test8"), QVariant((int)6));
2816 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2817 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2818 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2819 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2824 void tst_qdeclarativeecmascript::propertySplicing()
2826 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2828 QObject *object = component.create();
2829 QVERIFY(object != 0);
2831 QCOMPARE(object->property("test").toBool(), true);
2837 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2839 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2841 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2842 QVERIFY(object != 0);
2844 MyQmlObject::MyType type;
2845 type.value = 0x8971123;
2846 emit object->signalWithUnknownType(type);
2848 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2850 QCOMPARE(result.value, type.value);
2856 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2858 QTest::addColumn<QString>("expression");
2859 QTest::addColumn<QString>("compare");
2861 QString compareStrict("(function(a, b) { return a === b; })");
2862 QTest::newRow("true") << "true" << compareStrict;
2863 QTest::newRow("undefined") << "undefined" << compareStrict;
2864 QTest::newRow("null") << "null" << compareStrict;
2865 QTest::newRow("123") << "123" << compareStrict;
2866 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2868 QString comparePropertiesStrict(
2870 " if (typeof b != 'object')"
2872 " var props = Object.getOwnPropertyNames(b);"
2873 " for (var i = 0; i < props.length; ++i) {"
2874 " var p = props[i];"
2875 " return arguments.callee(a[p], b[p]);"
2878 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2879 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2882 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2884 QFETCH(QString, expression);
2885 QFETCH(QString, compare);
2887 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2888 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2889 QVERIFY(object != 0);
2891 QJSValue value = engine.evaluate(expression);
2892 QVERIFY(!engine.hasUncaughtException());
2893 object->setProperty("expression", expression);
2894 object->setProperty("compare", compare);
2895 object->setProperty("pass", false);
2897 emit object->signalWithVariant(QVariant::fromValue(value));
2898 QVERIFY(object->property("pass").toBool());
2901 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2903 signalWithJSValueInVariant_data();
2906 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2908 QFETCH(QString, expression);
2909 QFETCH(QString, compare);
2911 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2912 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2913 QVERIFY(object != 0);
2916 QJSValue value = engine2.evaluate(expression);
2917 QVERIFY(!engine2.hasUncaughtException());
2918 object->setProperty("expression", expression);
2919 object->setProperty("compare", compare);
2920 object->setProperty("pass", false);
2922 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2923 emit object->signalWithVariant(QVariant::fromValue(value));
2924 QVERIFY(!object->property("pass").toBool());
2927 void tst_qdeclarativeecmascript::moduleApi_data()
2929 QTest::addColumn<QUrl>("testfile");
2930 QTest::addColumn<QString>("errorMessage");
2931 QTest::addColumn<QStringList>("warningMessages");
2932 QTest::addColumn<QStringList>("readProperties");
2933 QTest::addColumn<QVariantList>("readExpectedValues");
2934 QTest::addColumn<QStringList>("writeProperties");
2935 QTest::addColumn<QVariantList>("writeValues");
2936 QTest::addColumn<QStringList>("readBackProperties");
2937 QTest::addColumn<QVariantList>("readBackExpectedValues");
2939 QTest::newRow("qobject, register + read + method")
2940 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2943 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2944 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2945 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2951 QTest::newRow("script, register + read")
2952 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2955 << (QStringList() << "scriptTest")
2956 << (QVariantList() << 13)
2962 QTest::newRow("qobject, caching + read")
2963 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2966 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2967 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2973 QTest::newRow("script, caching + read")
2974 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2977 << (QStringList() << "scriptTest")
2978 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2984 QTest::newRow("qobject, writing + readonly constraints")
2985 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2987 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2988 << (QStringList() << "readOnlyProperty" << "writableProperty")
2989 << (QVariantList() << 20 << 50)
2990 << (QStringList() << "firstProperty" << "writableProperty")
2991 << (QVariantList() << 30 << 30)
2992 << (QStringList() << "readOnlyProperty" << "writableProperty")
2993 << (QVariantList() << 20 << 30);
2995 QTest::newRow("script, writing + readonly constraints")
2996 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2998 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2999 << (QStringList() << "readBack" << "unchanged")
3000 << (QVariantList() << 13 << 42)
3001 << (QStringList() << "firstProperty" << "secondProperty")
3002 << (QVariantList() << 30 << 30)
3003 << (QStringList() << "readBack" << "unchanged")
3004 << (QVariantList() << 30 << 42);
3006 QTest::newRow("qobject module API enum values in JS")
3007 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3010 << (QStringList() << "enumValue" << "enumMethod")
3011 << (QVariantList() << 42 << 30)
3017 QTest::newRow("qobject, invalid major version fail")
3018 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3019 << QString("QDeclarativeComponent: Component is not ready")
3028 QTest::newRow("qobject, invalid minor version fail")
3029 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3030 << QString("QDeclarativeComponent: Component is not ready")
3040 void tst_qdeclarativeecmascript::moduleApi()
3042 QFETCH(QUrl, testfile);
3043 QFETCH(QString, errorMessage);
3044 QFETCH(QStringList, warningMessages);
3045 QFETCH(QStringList, readProperties);
3046 QFETCH(QVariantList, readExpectedValues);
3047 QFETCH(QStringList, writeProperties);
3048 QFETCH(QVariantList, writeValues);
3049 QFETCH(QStringList, readBackProperties);
3050 QFETCH(QVariantList, readBackExpectedValues);
3052 QDeclarativeComponent component(&engine, testfile);
3054 if (!errorMessage.isEmpty())
3055 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3057 if (warningMessages.size())
3058 foreach (const QString &warning, warningMessages)
3059 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3061 QObject *object = component.create();
3062 if (!errorMessage.isEmpty()) {
3063 QVERIFY(object == 0);
3065 QVERIFY(object != 0);
3066 for (int i = 0; i < readProperties.size(); ++i)
3067 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3068 for (int i = 0; i < writeProperties.size(); ++i)
3069 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3070 for (int i = 0; i < readBackProperties.size(); ++i)
3071 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3076 void tst_qdeclarativeecmascript::importScripts_data()
3078 QTest::addColumn<QUrl>("testfile");
3079 QTest::addColumn<QString>("errorMessage");
3080 QTest::addColumn<QStringList>("warningMessages");
3081 QTest::addColumn<QStringList>("propertyNames");
3082 QTest::addColumn<QVariantList>("propertyValues");
3084 QTest::newRow("basic functionality")
3085 << TEST_FILE("jsimport/testImport.qml")
3088 << (QStringList() << QLatin1String("importedScriptStringValue")
3089 << QLatin1String("importedScriptFunctionValue")
3090 << QLatin1String("importedModuleAttachedPropertyValue")
3091 << QLatin1String("importedModuleEnumValue"))
3092 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3097 QTest::newRow("import scoping")
3098 << TEST_FILE("jsimport/testImportScoping.qml")
3101 << (QStringList() << QLatin1String("componentError"))
3102 << (QVariantList() << QVariant(5));
3104 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3105 << TEST_FILE("jsimportfail/failOne.qml")
3107 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3108 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3109 << (QVariantList() << QVariant(QString()));
3111 QTest::newRow("javascript imports in an import should be private to the import scope")
3112 << TEST_FILE("jsimportfail/failTwo.qml")
3114 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3115 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3116 << (QVariantList() << QVariant(QString()));
3118 QTest::newRow("module imports in an import should be private to the import scope")
3119 << TEST_FILE("jsimportfail/failThree.qml")
3121 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3122 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3123 << (QVariantList() << QVariant(false));
3125 QTest::newRow("typenames in an import should be private to the import scope")
3126 << TEST_FILE("jsimportfail/failFour.qml")
3128 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3129 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3130 << (QVariantList() << QVariant(0));
3132 QTest::newRow("import with imports has it's own activation scope")
3133 << TEST_FILE("jsimportfail/failFive.qml")
3135 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3136 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3137 << (QStringList() << QLatin1String("componentError"))
3138 << (QVariantList() << QVariant(0));
3140 QTest::newRow("import pragma library script")
3141 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3144 << (QStringList() << QLatin1String("testValue"))
3145 << (QVariantList() << QVariant(31));
3147 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3148 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3151 << (QStringList() << QLatin1String("testValue"))
3152 << (QVariantList() << QVariant(0));
3154 QTest::newRow("import pragma library script which has an import")
3155 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3158 << (QStringList() << QLatin1String("testValue"))
3159 << (QVariantList() << QVariant(55));
3161 QTest::newRow("import pragma library script which has a pragma library import")
3162 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3165 << (QStringList() << QLatin1String("testValue"))
3166 << (QVariantList() << QVariant(18));
3169 void tst_qdeclarativeecmascript::importScripts()
3171 QFETCH(QUrl, testfile);
3172 QFETCH(QString, errorMessage);
3173 QFETCH(QStringList, warningMessages);
3174 QFETCH(QStringList, propertyNames);
3175 QFETCH(QVariantList, propertyValues);
3177 QDeclarativeComponent component(&engine, testfile);
3179 if (!errorMessage.isEmpty())
3180 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3182 if (warningMessages.size())
3183 foreach (const QString &warning, warningMessages)
3184 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3186 QObject *object = component.create();
3187 if (!errorMessage.isEmpty()) {
3188 QVERIFY(object == 0);
3190 QVERIFY(object != 0);
3191 for (int i = 0; i < propertyNames.size(); ++i)
3192 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3197 void tst_qdeclarativeecmascript::scarceResources()
3199 QPixmap origPixmap(100, 100);
3200 origPixmap.fill(Qt::blue);
3202 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3203 ScarceResourceObject *eo = 0;
3204 QObject *object = 0;
3206 // in the following three cases, the instance created from the component
3207 // has a property which is a copy of the scarce resource; hence, the
3208 // resource should NOT be detached prior to deletion of the object instance,
3209 // unless the resource is destroyed explicitly.
3210 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3211 object = component.create();
3212 QVERIFY(object != 0);
3213 QVERIFY(object->property("scarceResourceCopy").isValid());
3214 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3215 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3216 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3217 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3220 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3221 object = componentTwo.create();
3222 QVERIFY(object != 0);
3223 QVERIFY(object->property("scarceResourceCopy").isValid());
3224 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3225 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3226 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3227 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3230 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3231 object = componentThree.create();
3232 QVERIFY(object != 0);
3233 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3234 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3235 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3236 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3239 // in the following three cases, no other copy should exist in memory,
3240 // and so it should be detached (unless explicitly preserved).
3241 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3242 object = componentFour.create();
3243 QVERIFY(object != 0);
3244 QVERIFY(object->property("scarceResourceTest").isValid());
3245 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3246 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3247 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3248 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3251 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3252 object = componentFive.create();
3253 QVERIFY(object != 0);
3254 QVERIFY(object->property("scarceResourceTest").isValid());
3255 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3256 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3257 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3258 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3261 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3262 object = componentSix.create();
3263 QVERIFY(object != 0);
3264 QVERIFY(object->property("scarceResourceTest").isValid());
3265 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3266 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3267 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3268 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3271 // test that scarce resources are handled correctly for imports
3272 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3273 object = componentSeven.create();
3274 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3275 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3278 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3279 object = componentEight.create();
3280 QVERIFY(object != 0);
3281 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3282 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3285 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3286 object = componentNine.create();
3287 QVERIFY(object != 0);
3288 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3289 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3290 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3291 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3292 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3293 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3296 // test that scarce resources are handled properly in signal invocation
3297 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3298 object = componentTen.create();
3299 QVERIFY(object != 0);
3300 QObject *srsc = object->findChild<QObject*>("srsc");
3302 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3303 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3304 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3305 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3306 QMetaObject::invokeMethod(srsc, "testSignal");
3307 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3308 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3309 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3310 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3311 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3312 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3313 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3314 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3315 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3316 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3319 // test that scarce resources are handled properly from js functions in qml files
3320 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3321 object = componentEleven.create();
3322 QVERIFY(object != 0);
3323 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3324 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3325 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3326 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3327 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3328 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3329 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3330 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3331 QMetaObject::invokeMethod(object, "releaseScarceResource");
3332 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3333 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3334 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3335 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3338 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3339 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3340 object = componentTwelve.create();
3341 QVERIFY(object != 0);
3342 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3343 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3344 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3345 QString srp_name = object->property("srp_name").toString();
3346 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3347 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3348 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3349 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3350 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3351 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3352 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3356 void tst_qdeclarativeecmascript::propertyChangeSlots()
3358 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3359 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3360 QObject *object = component.create();
3361 QVERIFY(object != 0);
3364 // ensure that invalid property names fail properly.
3365 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3366 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3367 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3368 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3369 object = e1.create();
3370 QVERIFY(object == 0);
3373 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3374 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3375 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3376 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3377 object = e2.create();
3378 QVERIFY(object == 0);
3381 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3382 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3383 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3384 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3385 object = e3.create();
3386 QVERIFY(object == 0);
3389 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3390 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3391 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3392 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3393 object = e4.create();
3394 QVERIFY(object == 0);
3398 void tst_qdeclarativeecmascript::propertyVar_data()
3400 QTest::addColumn<QUrl>("qmlFile");
3403 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3404 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3405 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3406 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3407 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3408 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3409 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3410 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3411 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3414 void tst_qdeclarativeecmascript::propertyVar()
3416 QFETCH(QUrl, qmlFile);
3418 QDeclarativeComponent component(&engine, qmlFile);
3419 QObject *object = component.create();
3420 QVERIFY(object != 0);
3422 QCOMPARE(object->property("test").toBool(), true);
3427 // Tests that we can write QVariant values to var properties from C++
3428 void tst_qdeclarativeecmascript::propertyVarCpp()
3430 QObject *object = 0;
3432 // ensure that writing to and reading from a var property from cpp works as required.
3433 // Literal values stored in var properties can be read and written as QVariants
3434 // of a specific type, whereas object values are read as QVariantMaps.
3435 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3436 object = component.create();
3437 QVERIFY(object != 0);
3438 // assign int to property var that currently has int assigned
3439 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3440 QCOMPARE(object->property("varBound"), QVariant(15));
3441 QCOMPARE(object->property("intBound"), QVariant(15));
3442 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3443 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3444 // assign string to property var that current has bool assigned
3445 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3446 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3447 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3448 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3449 // now enforce behaviour when accessing JavaScript objects from cpp.
3450 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3454 static void gc(QDeclarativeEngine &engine)
3456 engine.collectGarbage();
3457 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3460 void tst_qdeclarativeecmascript::propertyVarOwnership()
3462 // Referenced JS objects are not collected
3464 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3465 QObject *object = component.create();
3466 QVERIFY(object != 0);
3467 QCOMPARE(object->property("test").toBool(), false);
3468 QMetaObject::invokeMethod(object, "runTest");
3469 QCOMPARE(object->property("test").toBool(), true);
3472 // Referenced JS objects are not collected
3474 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3475 QObject *object = component.create();
3476 QVERIFY(object != 0);
3477 QCOMPARE(object->property("test").toBool(), false);
3478 QMetaObject::invokeMethod(object, "runTest");
3479 QCOMPARE(object->property("test").toBool(), true);
3482 // Qt objects are not collected until they've been dereferenced
3484 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3485 QObject *object = component.create();
3486 QVERIFY(object != 0);
3488 QCOMPARE(object->property("test2").toBool(), false);
3489 QCOMPARE(object->property("test2").toBool(), false);
3491 QMetaObject::invokeMethod(object, "runTest");
3492 QCOMPARE(object->property("test1").toBool(), true);
3494 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3495 QVERIFY(!referencedObject.isNull());
3497 QVERIFY(!referencedObject.isNull());
3499 QMetaObject::invokeMethod(object, "runTest2");
3500 QCOMPARE(object->property("test2").toBool(), true);
3502 QVERIFY(referencedObject.isNull());
3506 // Self reference does not prevent Qt object collection
3508 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3509 QObject *object = component.create();
3510 QVERIFY(object != 0);
3512 QCOMPARE(object->property("test").toBool(), true);
3514 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3515 QVERIFY(!referencedObject.isNull());
3517 QVERIFY(!referencedObject.isNull());
3519 QMetaObject::invokeMethod(object, "runTest");
3521 QVERIFY(referencedObject.isNull());
3527 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3529 // The childObject has a reference to a different QObject. We want to ensure
3530 // that the different item will not be cleaned up until required. IE, the childObject
3531 // has implicit ownership of the constructed QObject.
3532 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3533 QObject *object = component.create();
3534 QVERIFY(object != 0);
3535 QMetaObject::invokeMethod(object, "assignCircular");
3536 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3537 QObject *rootObject = object->property("vp").value<QObject*>();
3538 QVERIFY(rootObject != 0);
3539 QObject *childObject = rootObject->findChild<QObject*>("text");
3540 QVERIFY(childObject != 0);
3541 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3542 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3543 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3544 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3545 QVERIFY(!qobjectGuard.isNull());
3546 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3547 QVERIFY(!qobjectGuard.isNull());
3548 QMetaObject::invokeMethod(object, "deassignCircular");
3549 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3550 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3554 void tst_qdeclarativeecmascript::propertyVarReparent()
3556 // ensure that nothing breaks if we re-parent objects
3557 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3558 QObject *object = component.create();
3559 QVERIFY(object != 0);
3560 QMetaObject::invokeMethod(object, "assignVarProp");
3561 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3562 QObject *rect = object->property("vp").value<QObject*>();
3563 QObject *text = rect->findChild<QObject*>("textOne");
3564 QObject *text2 = rect->findChild<QObject*>("textTwo");
3565 QWeakPointer<QObject> rectGuard(rect);
3566 QWeakPointer<QObject> textGuard(text);
3567 QWeakPointer<QObject> text2Guard(text2);
3568 QVERIFY(!rectGuard.isNull());
3569 QVERIFY(!textGuard.isNull());
3570 QVERIFY(!text2Guard.isNull());
3571 QCOMPARE(text->property("textCanary").toInt(), 11);
3572 QCOMPARE(text2->property("textCanary").toInt(), 12);
3573 // now construct an image which we will reparent.
3574 QMetaObject::invokeMethod(text2, "constructQObject");
3575 QObject *image = text2->property("vp").value<QObject*>();
3576 QWeakPointer<QObject> imageGuard(image);
3577 QVERIFY(!imageGuard.isNull());
3578 QCOMPARE(image->property("imageCanary").toInt(), 13);
3579 // now reparent the "Image" object (currently, it has JS ownership)
3580 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3581 QMetaObject::invokeMethod(text2, "deassignVp");
3582 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3583 QCOMPARE(text->property("textCanary").toInt(), 11);
3584 QCOMPARE(text2->property("textCanary").toInt(), 22);
3585 QVERIFY(!imageGuard.isNull()); // should still be alive.
3586 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
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 now have been deleted, due to parent being deleted.
3593 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3595 // sometimes reparenting can cause problems
3596 // (eg, if the ctxt is collected, varproperties are no longer available)
3597 // this test ensures that no crash occurs in that situation.
3598 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3599 QObject *object = component.create();
3600 QVERIFY(object != 0);
3601 QMetaObject::invokeMethod(object, "assignVarProp");
3602 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3603 QObject *rect = object->property("vp").value<QObject*>();
3604 QObject *text = rect->findChild<QObject*>("textOne");
3605 QObject *text2 = rect->findChild<QObject*>("textTwo");
3606 QWeakPointer<QObject> rectGuard(rect);
3607 QWeakPointer<QObject> textGuard(text);
3608 QWeakPointer<QObject> text2Guard(text2);
3609 QVERIFY(!rectGuard.isNull());
3610 QVERIFY(!textGuard.isNull());
3611 QVERIFY(!text2Guard.isNull());
3612 QCOMPARE(text->property("textCanary").toInt(), 11);
3613 QCOMPARE(text2->property("textCanary").toInt(), 12);
3614 // now construct an image which we will reparent.
3615 QMetaObject::invokeMethod(text2, "constructQObject");
3616 QObject *image = text2->property("vp").value<QObject*>();
3617 QWeakPointer<QObject> imageGuard(image);
3618 QVERIFY(!imageGuard.isNull());
3619 QCOMPARE(image->property("imageCanary").toInt(), 13);
3620 // now reparent the "Image" object (currently, it has JS ownership)
3621 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3622 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3623 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3624 QVERIFY(!imageGuard.isNull()); // should still be alive.
3625 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3627 QVERIFY(imageGuard.isNull()); // should now be dead.
3630 void tst_qdeclarativeecmascript::propertyVarCircular()
3632 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3633 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3634 QObject *object = component.create();
3635 QVERIFY(object != 0);
3636 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3637 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3638 QCOMPARE(object->property("canaryInt"), QVariant(5));
3639 QVariant canaryResourceVariant = object->property("canaryResource");
3640 QVERIFY(canaryResourceVariant.isValid());
3641 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3642 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3643 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3644 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3645 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3646 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3647 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3648 QCOMPARE(object->property("canaryInt"), QVariant(2));
3649 QCOMPARE(object->property("canaryResource"), QVariant(1));
3650 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3654 void tst_qdeclarativeecmascript::propertyVarCircular2()
3656 // track deletion of JS-owned parent item with Cpp-owned child
3657 // where the child has a var property referencing its parent.
3658 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3659 QObject *object = component.create();
3660 QVERIFY(object != 0);
3661 QMetaObject::invokeMethod(object, "assignCircular");
3662 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3663 QObject *rootObject = object->property("vp").value<QObject*>();
3664 QVERIFY(rootObject != 0);
3665 QObject *childObject = rootObject->findChild<QObject*>("text");
3666 QVERIFY(childObject != 0);
3667 QWeakPointer<QObject> rootObjectTracker(rootObject);
3668 QVERIFY(!rootObjectTracker.isNull());
3669 QWeakPointer<QObject> childObjectTracker(childObject);
3670 QVERIFY(!childObjectTracker.isNull());
3672 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3673 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3674 QMetaObject::invokeMethod(object, "deassignCircular");
3675 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3676 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3677 QVERIFY(childObjectTracker.isNull()); // should have been collected
3681 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3683 *(int*)(parameter) += 1;
3684 qPersistentDispose(object);
3687 void tst_qdeclarativeecmascript::propertyVarInheritance()
3689 int propertyVarWeakRefCallbackCount = 0;
3691 // enforce behaviour regarding element inheritance - ensure handle disposal.
3692 // The particular component under test here has a chain of references.
3693 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3694 QObject *object = component.create();
3695 QVERIFY(object != 0);
3696 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3697 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3698 // we want to be able to track when the varProperties array of the last metaobject is disposed
3699 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3700 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*>();
3701 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3702 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3703 v8::Persistent<v8::Value> icoCanaryHandle;
3704 v8::Persistent<v8::Value> ccoCanaryHandle;
3707 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3708 // public function which can return us a handle to something in the varProperties array.
3709 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3710 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3711 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3712 // as the varproperties array of each vmemo still references the resource.
3713 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3714 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3716 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3718 // now we deassign the var prop, which should trigger collection of item subtrees.
3719 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3720 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3721 // ensure that there are only weak handles to the underlying varProperties array remaining.
3723 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3725 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3726 // to what remains are weak, all varProperties arrays must have been collected.
3729 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3731 int propertyVarWeakRefCallbackCount = 0;
3733 // The particular component under test here does NOT have a chain of references; the
3734 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3735 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3736 QObject *object = component.create();
3737 QVERIFY(object != 0);
3738 QMetaObject::invokeMethod(object, "assignCircular");
3739 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3740 QObject *rootObject = object->property("vp").value<QObject*>();
3741 QVERIFY(rootObject != 0);
3742 QObject *childObject = rootObject->findChild<QObject*>("text");
3743 QVERIFY(childObject != 0);
3744 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3745 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3746 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3749 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3750 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3751 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3753 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3754 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3756 QMetaObject::invokeMethod(object, "deassignCircular");
3757 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3758 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3762 // Ensure that QObject type conversion works on binding assignment
3763 void tst_qdeclarativeecmascript::elementAssign()
3765 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3767 QObject *object = component.create();
3768 QVERIFY(object != 0);
3770 QCOMPARE(object->property("test").toBool(), true);
3776 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3778 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3780 QObject *object = component.create();
3781 QVERIFY(object != 0);
3783 QCOMPARE(object->property("test").toBool(), true);
3789 void tst_qdeclarativeecmascript::objectConversion()
3791 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3793 QObject *object = component.create();
3794 QVERIFY(object != 0);
3796 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3797 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3804 void tst_qdeclarativeecmascript::booleanConversion()
3806 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3808 QObject *object = component.create();
3809 QVERIFY(object != 0);
3811 QCOMPARE(object->property("test_true1").toBool(), true);
3812 QCOMPARE(object->property("test_true2").toBool(), true);
3813 QCOMPARE(object->property("test_true3").toBool(), true);
3814 QCOMPARE(object->property("test_true4").toBool(), true);
3815 QCOMPARE(object->property("test_true5").toBool(), true);
3817 QCOMPARE(object->property("test_false1").toBool(), false);
3818 QCOMPARE(object->property("test_false2").toBool(), false);
3819 QCOMPARE(object->property("test_false3").toBool(), false);
3824 void tst_qdeclarativeecmascript::handleReferenceManagement()
3829 // Linear QObject reference
3830 QDeclarativeEngine hrmEngine;
3831 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3832 QObject *object = component.create();
3833 QVERIFY(object != 0);
3834 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3835 cro->setDtorCount(&dtorCount);
3836 QMetaObject::invokeMethod(object, "createReference");
3838 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3840 hrmEngine.collectGarbage();
3841 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3842 QCOMPARE(dtorCount, 3);
3847 // Circular QObject reference
3848 QDeclarativeEngine hrmEngine;
3849 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3850 QObject *object = component.create();
3851 QVERIFY(object != 0);
3852 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3853 cro->setDtorCount(&dtorCount);
3854 QMetaObject::invokeMethod(object, "circularReference");
3856 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3858 hrmEngine.collectGarbage();
3859 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3860 QCOMPARE(dtorCount, 3);
3865 // Linear handle reference
3866 QDeclarativeEngine hrmEngine;
3867 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3868 QObject *object = component.create();
3869 QVERIFY(object != 0);
3870 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3872 crh->setDtorCount(&dtorCount);
3873 QMetaObject::invokeMethod(object, "createReference");
3874 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3875 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3876 QVERIFY(first != 0);
3877 QVERIFY(second != 0);
3878 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3879 // now we have to reparent second and make second owned by JS.
3880 second->setParent(0);
3881 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3883 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3885 hrmEngine.collectGarbage();
3886 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3887 QCOMPARE(dtorCount, 3);
3892 // Circular handle reference
3893 QDeclarativeEngine hrmEngine;
3894 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3895 QObject *object = component.create();
3896 QVERIFY(object != 0);
3897 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3899 crh->setDtorCount(&dtorCount);
3900 QMetaObject::invokeMethod(object, "circularReference");
3901 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3902 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3903 QVERIFY(first != 0);
3904 QVERIFY(second != 0);
3905 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3906 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3907 // now we have to reparent and change ownership.
3908 first->setParent(0);
3909 second->setParent(0);
3910 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3911 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3913 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3915 hrmEngine.collectGarbage();
3916 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3917 QCOMPARE(dtorCount, 3);
3922 // multiple engine interaction - linear reference
3923 QDeclarativeEngine hrmEngine1;
3924 QDeclarativeEngine hrmEngine2;
3925 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3926 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3927 QObject *object1 = component1.create();
3928 QObject *object2 = component2.create();
3929 QVERIFY(object1 != 0);
3930 QVERIFY(object2 != 0);
3931 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3932 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3935 crh1->setDtorCount(&dtorCount);
3936 crh2->setDtorCount(&dtorCount);
3937 QMetaObject::invokeMethod(object1, "createReference");
3938 QMetaObject::invokeMethod(object2, "createReference");
3939 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3940 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3941 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3942 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3943 QVERIFY(first1 != 0);
3944 QVERIFY(second1 != 0);
3945 QVERIFY(first2 != 0);
3946 QVERIFY(second2 != 0);
3947 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3948 // now we have to reparent second2 and make second2 owned by JS.
3949 second2->setParent(0);
3950 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3952 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3953 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3956 hrmEngine1.collectGarbage();
3957 hrmEngine2.collectGarbage();
3958 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3959 QCOMPARE(dtorCount, 6);
3964 // multiple engine interaction - circular reference
3965 QDeclarativeEngine hrmEngine1;
3966 QDeclarativeEngine hrmEngine2;
3967 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3968 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3969 QObject *object1 = component1.create();
3970 QObject *object2 = component2.create();
3971 QVERIFY(object1 != 0);
3972 QVERIFY(object2 != 0);
3973 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3974 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3977 crh1->setDtorCount(&dtorCount);
3978 crh2->setDtorCount(&dtorCount);
3979 QMetaObject::invokeMethod(object1, "createReference");
3980 QMetaObject::invokeMethod(object2, "createReference");
3981 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3982 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3983 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3984 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3985 QVERIFY(first1 != 0);
3986 QVERIFY(second1 != 0);
3987 QVERIFY(first2 != 0);
3988 QVERIFY(second2 != 0);
3989 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3990 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3991 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3992 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3993 // now we have to reparent and change ownership to JS.
3994 first1->setParent(0);
3995 second1->setParent(0);
3996 first2->setParent(0);
3997 second2->setParent(0);
3998 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3999 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4000 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4001 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4003 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4004 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4007 hrmEngine1.collectGarbage();
4008 hrmEngine2.collectGarbage();
4009 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4010 QCOMPARE(dtorCount, 6);
4015 // multiple engine interaction - linear reference with engine deletion
4016 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4017 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4018 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4019 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4020 QObject *object1 = component1.create();
4021 QObject *object2 = component2.create();
4022 QVERIFY(object1 != 0);
4023 QVERIFY(object2 != 0);
4024 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4025 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4028 crh1->setDtorCount(&dtorCount);
4029 crh2->setDtorCount(&dtorCount);
4030 QMetaObject::invokeMethod(object1, "createReference");
4031 QMetaObject::invokeMethod(object2, "createReference");
4032 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4033 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4034 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4035 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4036 QVERIFY(first1 != 0);
4037 QVERIFY(second1 != 0);
4038 QVERIFY(first2 != 0);
4039 QVERIFY(second2 != 0);
4040 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4041 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4042 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4043 // now we have to reparent and change ownership to JS.
4044 first1->setParent(crh1);
4045 second1->setParent(0);
4046 first2->setParent(0);
4047 second2->setParent(0);
4048 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4049 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4050 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4052 QCOMPARE(dtorCount, 0);
4055 QCOMPARE(dtorCount, 0);
4058 hrmEngine1->collectGarbage();
4059 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4060 QCOMPARE(dtorCount, 6);
4065 void tst_qdeclarativeecmascript::stringArg()
4067 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4068 QObject *object = component.create();
4069 QVERIFY(object != 0);
4070 QMetaObject::invokeMethod(object, "success");
4071 QVERIFY(object->property("returnValue").toBool());
4073 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4074 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4075 QMetaObject::invokeMethod(object, "failure");
4076 QVERIFY(object->property("returnValue").toBool());
4081 void tst_qdeclarativeecmascript::readonlyDeclaration()
4083 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4085 QObject *object = component.create();
4086 QVERIFY(object != 0);
4088 QCOMPARE(object->property("test").toBool(), true);
4093 Q_DECLARE_METATYPE(QList<int>)
4094 Q_DECLARE_METATYPE(QList<qreal>)
4095 Q_DECLARE_METATYPE(QList<bool>)
4096 Q_DECLARE_METATYPE(QList<QString>)
4097 Q_DECLARE_METATYPE(QList<QUrl>)
4098 void tst_qdeclarativeecmascript::sequenceConversionRead()
4101 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4102 QDeclarativeComponent component(&engine, qmlFile);
4103 QObject *object = component.create();
4104 QVERIFY(object != 0);
4105 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4108 QMetaObject::invokeMethod(object, "readSequences");
4109 QList<int> intList; intList << 1 << 2 << 3 << 4;
4110 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4111 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4112 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4113 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4114 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4115 QList<bool> boolList; boolList << true << false << true << false;
4116 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4117 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4118 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4119 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4120 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4121 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4122 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4123 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4124 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4125 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4126 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4128 QMetaObject::invokeMethod(object, "readSequenceElements");
4129 QCOMPARE(object->property("intVal").toInt(), 2);
4130 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4131 QCOMPARE(object->property("boolVal").toBool(), false);
4132 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4133 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4134 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4136 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4137 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4139 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4140 QDeclarativeProperty seqProp(seq, "intListProperty");
4141 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4142 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4143 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4145 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4146 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4152 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4153 QDeclarativeComponent component(&engine, qmlFile);
4154 QObject *object = component.create();
4155 QVERIFY(object != 0);
4156 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4159 // we haven't registered QList<QPoint> as a sequence type.
4160 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4161 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4162 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4163 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4165 QMetaObject::invokeMethod(object, "performTest");
4167 // QList<QPoint> has not been registered as a sequence type.
4168 QCOMPARE(object->property("pointListLength").toInt(), 0);
4169 QVERIFY(!object->property("pointList").isValid());
4170 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4171 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4172 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4178 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4181 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4182 QDeclarativeComponent component(&engine, qmlFile);
4183 QObject *object = component.create();
4184 QVERIFY(object != 0);
4185 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4188 QMetaObject::invokeMethod(object, "writeSequences");
4189 QCOMPARE(object->property("success").toBool(), true);
4191 QMetaObject::invokeMethod(object, "writeSequenceElements");
4192 QCOMPARE(object->property("success").toBool(), true);
4194 QMetaObject::invokeMethod(object, "writeOtherElements");
4195 QCOMPARE(object->property("success").toBool(), true);
4197 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4198 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4204 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4205 QDeclarativeComponent component(&engine, qmlFile);
4206 QObject *object = component.create();
4207 QVERIFY(object != 0);
4208 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4211 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4212 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4213 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4215 QMetaObject::invokeMethod(object, "performTest");
4217 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4218 QCOMPARE(seq->pointListProperty(), pointList);
4224 void tst_qdeclarativeecmascript::sequenceConversionArray()
4226 // ensure that in JS the returned sequences act just like normal JS Arrays.
4227 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4228 QDeclarativeComponent component(&engine, qmlFile);
4229 QObject *object = component.create();
4230 QVERIFY(object != 0);
4231 QMetaObject::invokeMethod(object, "indexedAccess");
4232 QVERIFY(object->property("success").toBool());
4233 QMetaObject::invokeMethod(object, "arrayOperations");
4234 QVERIFY(object->property("success").toBool());
4235 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4236 QVERIFY(object->property("success").toBool());
4237 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4238 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4242 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4244 // ensure that sequence conversion operations work correctly in a worker thread
4245 // and that serialisation between the main and worker thread succeeds.
4246 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4247 QDeclarativeComponent component(&engine, qmlFile);
4248 QObject *object = component.create();
4249 QVERIFY(object != 0);
4251 QMetaObject::invokeMethod(object, "testIntSequence");
4252 QTRY_VERIFY(object->property("finished").toBool());
4253 QVERIFY(object->property("success").toBool());
4255 QMetaObject::invokeMethod(object, "testQrealSequence");
4256 QTRY_VERIFY(object->property("finished").toBool());
4257 QVERIFY(object->property("success").toBool());
4259 QMetaObject::invokeMethod(object, "testBoolSequence");
4260 QTRY_VERIFY(object->property("finished").toBool());
4261 QVERIFY(object->property("success").toBool());
4263 QMetaObject::invokeMethod(object, "testStringSequence");
4264 QTRY_VERIFY(object->property("finished").toBool());
4265 QVERIFY(object->property("success").toBool());
4267 QMetaObject::invokeMethod(object, "testQStringSequence");
4268 QTRY_VERIFY(object->property("finished").toBool());
4269 QVERIFY(object->property("success").toBool());
4271 QMetaObject::invokeMethod(object, "testUrlSequence");
4272 QTRY_VERIFY(object->property("finished").toBool());
4273 QVERIFY(object->property("success").toBool());
4275 QMetaObject::invokeMethod(object, "testVariantSequence");
4276 QTRY_VERIFY(object->property("finished").toBool());
4277 QVERIFY(object->property("success").toBool());
4282 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4285 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4286 QDeclarativeComponent component(&engine, qmlFile);
4287 QObject *object = component.create();
4288 QVERIFY(object != 0);
4289 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4290 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4291 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4292 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4293 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4298 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4299 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4300 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4301 QDeclarativeComponent component(&engine, qmlFile);
4302 QObject *object = component.create();
4303 QVERIFY(object != 0);
4308 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4310 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4311 QDeclarativeComponent component(&engine, qmlFile);
4312 QObject *object = component.create();
4313 QVERIFY(object != 0);
4314 QMetaObject::invokeMethod(object, "testCopySequences");
4315 QCOMPARE(object->property("success").toBool(), true);
4316 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4317 QCOMPARE(object->property("success").toBool(), true);
4318 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4319 QCOMPARE(object->property("success").toBool(), true);
4323 // Test that assigning a null object works
4324 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4325 void tst_qdeclarativeecmascript::nullObjectBinding()
4327 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4329 QObject *object = component.create();
4330 QVERIFY(object != 0);
4332 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4337 // Test that bindings don't evaluate once the engine has been destroyed
4338 void tst_qdeclarativeecmascript::deletedEngine()
4340 QDeclarativeEngine *engine = new QDeclarativeEngine;
4341 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4343 QObject *object = component.create();
4344 QVERIFY(object != 0);
4346 QCOMPARE(object->property("a").toInt(), 39);
4347 object->setProperty("b", QVariant(9));
4348 QCOMPARE(object->property("a").toInt(), 117);
4352 QCOMPARE(object->property("a").toInt(), 117);
4353 object->setProperty("b", QVariant(10));
4354 QCOMPARE(object->property("a").toInt(), 117);
4359 // Test the crashing part of QTBUG-9705
4360 void tst_qdeclarativeecmascript::libraryScriptAssert()
4362 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4364 QObject *object = component.create();
4365 QVERIFY(object != 0);
4370 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4372 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4374 QObject *object = component.create();
4375 QVERIFY(object != 0);
4377 QCOMPARE(object->property("test1").toInt(), 10);
4378 QCOMPARE(object->property("test2").toInt(), 11);
4380 object->setProperty("runTest", true);
4382 QCOMPARE(object->property("test1"), QVariant());
4383 QCOMPARE(object->property("test2"), QVariant());
4389 void tst_qdeclarativeecmascript::qtbug_9792()
4391 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4393 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4395 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4396 QVERIFY(object != 0);
4398 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4399 object->basicSignal();
4403 transientErrorsMsgCount = 0;
4404 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4406 object->basicSignal();
4408 qInstallMsgHandler(old);
4410 QCOMPARE(transientErrorsMsgCount, 0);
4415 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4416 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4418 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4420 QObject *o = component.create();
4423 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4424 QVERIFY(nested != 0);
4426 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4429 nested = qvariant_cast<QObject *>(o->property("object"));
4430 QVERIFY(nested == 0);
4432 // If the bug is present, the next line will crash
4436 // Test that we shut down without stupid warnings
4437 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4440 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4442 QObject *o = component.create();
4444 transientErrorsMsgCount = 0;
4445 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4449 qInstallMsgHandler(old);
4451 QCOMPARE(transientErrorsMsgCount, 0);
4456 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4458 QObject *o = component.create();
4460 transientErrorsMsgCount = 0;
4461 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4465 qInstallMsgHandler(old);
4467 QCOMPARE(transientErrorsMsgCount, 0);
4471 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4474 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4476 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4479 QVERIFY(o->objectProperty() != 0);
4481 o->setProperty("runTest", true);
4483 QVERIFY(o->objectProperty() == 0);
4489 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4491 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4494 QVERIFY(o->objectProperty() == 0);
4500 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4502 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4504 QString url = component.url().toString();
4505 QString warning = url + ":4: Unable to assign a function to a property.";
4506 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4508 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4511 QVERIFY(!o->property("a").isValid());
4516 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4518 QFETCH(QString, triggerProperty);
4520 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4521 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4523 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4525 QVERIFY(!o->property("a").isValid());
4527 o->setProperty("aNumber", QVariant(5));
4528 o->setProperty(triggerProperty.toUtf8().constData(), true);
4529 QCOMPARE(o->property("a"), QVariant(50));
4531 o->setProperty("aNumber", QVariant(10));
4532 QCOMPARE(o->property("a"), QVariant(100));
4537 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4539 QTest::addColumn<QString>("triggerProperty");
4541 QTest::newRow("assign to property") << "assignToProperty";
4542 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4544 QTest::newRow("assign to value type") << "assignToValueType";
4546 QTest::newRow("use 'this'") << "assignWithThis";
4547 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4550 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4552 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4553 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4555 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4557 QVERIFY(!o->property("a").isValid());
4559 o->setProperty("assignFuncWithoutReturn", true);
4560 QVERIFY(!o->property("a").isValid());
4562 QString url = component.url().toString();
4563 QString warning = url + ":67: Unable to assign QString to int";
4564 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4565 o->setProperty("assignWrongType", true);
4567 warning = url + ":71: Unable to assign QString to int";
4568 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4569 o->setProperty("assignWrongTypeToValueType", true);
4574 void tst_qdeclarativeecmascript::eval()
4576 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4578 QObject *o = component.create();
4581 QCOMPARE(o->property("test1").toBool(), true);
4582 QCOMPARE(o->property("test2").toBool(), true);
4583 QCOMPARE(o->property("test3").toBool(), true);
4584 QCOMPARE(o->property("test4").toBool(), true);
4585 QCOMPARE(o->property("test5").toBool(), true);
4590 void tst_qdeclarativeecmascript::function()
4592 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4594 QObject *o = component.create();
4597 QCOMPARE(o->property("test1").toBool(), true);
4598 QCOMPARE(o->property("test2").toBool(), true);
4599 QCOMPARE(o->property("test3").toBool(), true);
4604 // Test the "Qt.include" method
4605 void tst_qdeclarativeecmascript::include()
4607 // Non-library relative include
4609 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4610 QObject *o = component.create();
4613 QCOMPARE(o->property("test0").toInt(), 99);
4614 QCOMPARE(o->property("test1").toBool(), true);
4615 QCOMPARE(o->property("test2").toBool(), true);
4616 QCOMPARE(o->property("test2_1").toBool(), true);
4617 QCOMPARE(o->property("test3").toBool(), true);
4618 QCOMPARE(o->property("test3_1").toBool(), true);
4623 // Library relative include
4625 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4626 QObject *o = component.create();
4629 QCOMPARE(o->property("test0").toInt(), 99);
4630 QCOMPARE(o->property("test1").toBool(), true);
4631 QCOMPARE(o->property("test2").toBool(), true);
4632 QCOMPARE(o->property("test2_1").toBool(), true);
4633 QCOMPARE(o->property("test3").toBool(), true);
4634 QCOMPARE(o->property("test3_1").toBool(), true);
4641 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4642 QObject *o = component.create();
4645 QCOMPARE(o->property("test1").toBool(), true);
4646 QCOMPARE(o->property("test2").toBool(), true);
4647 QCOMPARE(o->property("test3").toBool(), true);
4648 QCOMPARE(o->property("test4").toBool(), true);
4649 QCOMPARE(o->property("test5").toBool(), true);
4650 QCOMPARE(o->property("test6").toBool(), true);
4655 // Including file with ".pragma library"
4657 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4658 QObject *o = component.create();
4660 QCOMPARE(o->property("test1").toInt(), 100);
4667 TestHTTPServer server(8111);
4668 QVERIFY(server.isValid());
4669 server.serveDirectory(TESTDATA(""));
4671 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4672 QObject *o = component.create();
4675 QTRY_VERIFY(o->property("done").toBool() == true);
4676 QTRY_VERIFY(o->property("done2").toBool() == true);
4678 QCOMPARE(o->property("test1").toBool(), true);
4679 QCOMPARE(o->property("test2").toBool(), true);
4680 QCOMPARE(o->property("test3").toBool(), true);
4681 QCOMPARE(o->property("test4").toBool(), true);
4682 QCOMPARE(o->property("test5").toBool(), true);
4684 QCOMPARE(o->property("test6").toBool(), true);
4685 QCOMPARE(o->property("test7").toBool(), true);
4686 QCOMPARE(o->property("test8").toBool(), true);
4687 QCOMPARE(o->property("test9").toBool(), true);
4688 QCOMPARE(o->property("test10").toBool(), true);
4695 TestHTTPServer server(8111);
4696 QVERIFY(server.isValid());
4697 server.serveDirectory(TESTDATA(""));
4699 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4700 QObject *o = component.create();
4703 QTRY_VERIFY(o->property("done").toBool() == true);
4705 QCOMPARE(o->property("test1").toBool(), true);
4706 QCOMPARE(o->property("test2").toBool(), true);
4707 QCOMPARE(o->property("test3").toBool(), true);
4713 void tst_qdeclarativeecmascript::signalHandlers()
4715 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4716 QObject *o = component.create();
4719 QVERIFY(o->property("count").toInt() == 0);
4720 QMetaObject::invokeMethod(o, "testSignalCall");
4721 QCOMPARE(o->property("count").toInt(), 1);
4723 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4724 QCOMPARE(o->property("count").toInt(), 1);
4725 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4727 QVERIFY(o->property("funcCount").toInt() == 0);
4728 QMetaObject::invokeMethod(o, "testSignalConnection");
4729 QCOMPARE(o->property("funcCount").toInt(), 1);
4731 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4732 QCOMPARE(o->property("funcCount").toInt(), 2);
4734 QMetaObject::invokeMethod(o, "testSignalDefined");
4735 QCOMPARE(o->property("definedResult").toBool(), true);
4737 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4738 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4743 void tst_qdeclarativeecmascript::qtbug_10696()
4745 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4746 QObject *o = component.create();
4751 void tst_qdeclarativeecmascript::qtbug_11606()
4753 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4754 QObject *o = component.create();
4756 QCOMPARE(o->property("test").toBool(), true);
4760 void tst_qdeclarativeecmascript::qtbug_11600()
4762 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4763 QObject *o = component.create();
4765 QCOMPARE(o->property("test").toBool(), true);
4769 // Reading and writing non-scriptable properties should fail
4770 void tst_qdeclarativeecmascript::nonscriptable()
4772 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4773 QObject *o = component.create();
4775 QCOMPARE(o->property("readOk").toBool(), true);
4776 QCOMPARE(o->property("writeOk").toBool(), true);
4780 // deleteLater() should not be callable from QML
4781 void tst_qdeclarativeecmascript::deleteLater()
4783 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4784 QObject *o = component.create();
4786 QCOMPARE(o->property("test").toBool(), true);
4790 void tst_qdeclarativeecmascript::in()
4792 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4793 QObject *o = component.create();
4795 QCOMPARE(o->property("test1").toBool(), true);
4796 QCOMPARE(o->property("test2").toBool(), true);
4800 void tst_qdeclarativeecmascript::typeOf()
4802 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4803 QObject *o = component.create();
4805 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4806 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4807 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4808 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4809 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4810 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4811 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4812 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4813 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4814 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4819 void tst_qdeclarativeecmascript::sharedAttachedObject()
4821 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4822 QObject *o = component.create();
4824 QCOMPARE(o->property("test1").toBool(), true);
4825 QCOMPARE(o->property("test2").toBool(), true);
4830 void tst_qdeclarativeecmascript::objectName()
4832 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4833 QObject *o = component.create();
4836 QCOMPARE(o->property("test1").toString(), QString("hello"));
4837 QCOMPARE(o->property("test2").toString(), QString("ell"));
4839 o->setObjectName("world");
4841 QCOMPARE(o->property("test1").toString(), QString("world"));
4842 QCOMPARE(o->property("test2").toString(), QString("orl"));
4847 void tst_qdeclarativeecmascript::writeRemovesBinding()
4849 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4850 QObject *o = component.create();
4853 QCOMPARE(o->property("test").toBool(), true);
4858 // Test bindings assigned to alias properties actually assign to the alias' target
4859 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4861 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4862 QObject *o = component.create();
4865 QCOMPARE(o->property("test").toBool(), true);
4870 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4871 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4874 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4875 QObject *o = component.create();
4878 QCOMPARE(o->property("test").toBool(), true);
4884 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4885 QObject *o = component.create();
4888 QCOMPARE(o->property("test").toBool(), true);
4894 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4895 QObject *o = component.create();
4898 QCOMPARE(o->property("test").toBool(), true);
4904 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4905 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4908 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4909 QObject *o = component.create();
4912 QCOMPARE(o->property("test").toBool(), true);
4918 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4919 QObject *o = component.create();
4922 QCOMPARE(o->property("test").toBool(), true);
4928 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4929 QObject *o = component.create();
4932 QCOMPARE(o->property("test").toBool(), true);
4938 // Allow an alais to a composite element
4940 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4942 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4944 QObject *object = component.create();
4945 QVERIFY(object != 0);
4950 void tst_qdeclarativeecmascript::qtbug_20344()
4952 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
4954 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
4955 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
4957 QObject *object = component.create();
4958 QVERIFY(object != 0);
4963 void tst_qdeclarativeecmascript::revisionErrors()
4966 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4967 QString url = component.url().toString();
4969 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4970 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4971 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4973 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4974 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4975 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4976 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4977 QVERIFY(object != 0);
4981 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4982 QString url = component.url().toString();
4984 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4985 // method2, prop2 from MyRevisionedClass not available
4986 // method4, prop4 from MyRevisionedSubclass not available
4987 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4988 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4989 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4990 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4991 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4993 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4994 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4995 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4996 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4997 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4998 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4999 QVERIFY(object != 0);
5003 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5004 QString url = component.url().toString();
5006 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5007 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5008 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5009 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5010 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5011 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5012 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5013 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5014 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5015 QVERIFY(object != 0);
5020 void tst_qdeclarativeecmascript::revision()
5023 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5024 QString url = component.url().toString();
5026 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5027 QVERIFY(object != 0);
5031 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5032 QString url = component.url().toString();
5034 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5035 QVERIFY(object != 0);
5039 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5040 QString url = component.url().toString();
5042 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5043 QVERIFY(object != 0);
5046 // Test that non-root classes can resolve revisioned methods
5048 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5050 QObject *object = component.create();
5051 QVERIFY(object != 0);
5052 QCOMPARE(object->property("test").toReal(), 11.);
5057 void tst_qdeclarativeecmascript::realToInt()
5059 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5060 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5061 QVERIFY(object != 0);
5063 QMetaObject::invokeMethod(object, "test1");
5064 QCOMPARE(object->value(), int(4));
5065 QMetaObject::invokeMethod(object, "test2");
5066 QCOMPARE(object->value(), int(8));
5068 void tst_qdeclarativeecmascript::dynamicString()
5070 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5071 QObject *object = component.create();
5072 QVERIFY(object != 0);
5073 QCOMPARE(object->property("stringProperty").toString(),
5074 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5077 void tst_qdeclarativeecmascript::automaticSemicolon()
5079 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5080 QObject *object = component.create();
5081 QVERIFY(object != 0);
5084 void tst_qdeclarativeecmascript::unaryExpression()
5086 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5087 QObject *object = component.create();
5088 QVERIFY(object != 0);
5091 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5092 void tst_qdeclarativeecmascript::doubleEvaluate()
5094 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5095 QObject *object = component.create();
5096 QVERIFY(object != 0);
5097 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5099 QCOMPARE(wc->count(), 1);
5101 wc->setProperty("x", 9);
5103 QCOMPARE(wc->count(), 2);
5108 static QStringList messages;
5109 static void captureMsgHandler(QtMsgType, const char *msg)
5111 messages.append(QLatin1String(msg));
5114 void tst_qdeclarativeecmascript::nonNotifyable()
5116 QV4Compiler::enableV4(false);
5117 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5118 QV4Compiler::enableV4(true);
5120 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5122 QObject *object = component.create();
5123 qInstallMsgHandler(old);
5125 QVERIFY(object != 0);
5127 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5128 component.url().toString() +
5129 QLatin1String(":5 depends on non-NOTIFYable properties:");
5130 QString expected2 = QLatin1String(" ") +
5131 QLatin1String(object->metaObject()->className()) +
5132 QLatin1String("::value");
5134 QCOMPARE(messages.length(), 2);
5135 QCOMPARE(messages.at(0), expected1);
5136 QCOMPARE(messages.at(1), expected2);
5141 void tst_qdeclarativeecmascript::forInLoop()
5143 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5144 QObject *object = component.create();
5145 QVERIFY(object != 0);
5147 QMetaObject::invokeMethod(object, "listProperty");
5149 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5150 QCOMPARE(r.size(), 3);
5151 QCOMPARE(r[0],QLatin1String("0=obj1"));
5152 QCOMPARE(r[1],QLatin1String("1=obj2"));
5153 QCOMPARE(r[2],QLatin1String("2=obj3"));
5155 //TODO: should test for in loop for other objects (such as QObjects) as well.
5160 // An object the binding depends on is deleted while the binding is still running
5161 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5163 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5164 QObject *object = component.create();
5165 QVERIFY(object != 0);
5169 void tst_qdeclarativeecmascript::qtbug_22679()
5172 object.setStringProperty(QLatin1String("Please work correctly"));
5173 engine.rootContext()->setContextProperty("contextProp", &object);
5175 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5176 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5177 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5179 QObject *o = component.create();
5181 QCOMPARE(warningsSpy.count(), 0);
5185 void tst_qdeclarativeecmascript::qtbug_22843_data()
5187 QTest::addColumn<bool>("library");
5189 QTest::newRow("without .pragma library") << false;
5190 QTest::newRow("with .pragma library") << true;
5193 void tst_qdeclarativeecmascript::qtbug_22843()
5195 QFETCH(bool, library);
5197 QString fileName("qtbug_22843");
5199 fileName += QLatin1String(".library");
5200 fileName += QLatin1String(".qml");
5202 QDeclarativeComponent component(&engine, TEST_FILE(fileName));
5203 QString url = component.url().toString();
5204 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5205 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5207 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5208 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5209 for (int x = 0; x < 3; ++x) {
5210 warningsSpy.clear();
5211 // For libraries, only the first import attempt should produce a
5212 // SyntaxError warning; subsequent component creation should not
5213 // attempt to reload the script.
5214 bool expectSyntaxError = !library || (x == 0);
5215 if (expectSyntaxError)
5216 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5217 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5218 QObject *object = component.create();
5219 QVERIFY(object != 0);
5220 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5226 void tst_qdeclarativeecmascript::switchStatement()
5229 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.1.qml"));
5230 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5231 QVERIFY(object != 0);
5233 // `object->value()' is the number of executed statements
5235 object->setStringProperty("A");
5236 QCOMPARE(object->value(), 5);
5238 object->setStringProperty("S");
5239 QCOMPARE(object->value(), 3);
5241 object->setStringProperty("D");
5242 QCOMPARE(object->value(), 3);
5244 object->setStringProperty("F");
5245 QCOMPARE(object->value(), 4);
5247 object->setStringProperty("something else");
5248 QCOMPARE(object->value(), 1);
5252 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.2.qml"));
5253 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5254 QVERIFY(object != 0);
5256 // `object->value()' is the number of executed statements
5258 object->setStringProperty("A");
5259 QCOMPARE(object->value(), 5);
5261 object->setStringProperty("S");
5262 QCOMPARE(object->value(), 3);
5264 object->setStringProperty("D");
5265 QCOMPARE(object->value(), 3);
5267 object->setStringProperty("F");
5268 QCOMPARE(object->value(), 3);
5270 object->setStringProperty("something else");
5271 QCOMPARE(object->value(), 4);
5275 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.3.qml"));
5276 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5277 QVERIFY(object != 0);
5279 // `object->value()' is the number of executed statements
5281 object->setStringProperty("A");
5282 QCOMPARE(object->value(), 5);
5284 object->setStringProperty("S");
5285 QCOMPARE(object->value(), 3);
5287 object->setStringProperty("D");
5288 QCOMPARE(object->value(), 3);
5290 object->setStringProperty("F");
5291 QCOMPARE(object->value(), 3);
5293 object->setStringProperty("something else");
5294 QCOMPARE(object->value(), 6);
5298 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.4.qml"));
5299 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5300 QVERIFY(object != 0);
5302 // `object->value()' is the number of executed statements
5304 object->setStringProperty("A");
5305 QCOMPARE(object->value(), 5);
5307 object->setStringProperty("S");
5308 QCOMPARE(object->value(), 3);
5310 object->setStringProperty("D");
5311 QCOMPARE(object->value(), 3);
5313 object->setStringProperty("F");
5314 QCOMPARE(object->value(), 3);
5316 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5317 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5319 object->setStringProperty("something else");
5323 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.5.qml"));
5324 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5325 QVERIFY(object != 0);
5327 // `object->value()' is the number of executed statements
5329 object->setStringProperty("A");
5330 QCOMPARE(object->value(), 1);
5332 object->setStringProperty("S");
5333 QCOMPARE(object->value(), 1);
5335 object->setStringProperty("D");
5336 QCOMPARE(object->value(), 1);
5338 object->setStringProperty("F");
5339 QCOMPARE(object->value(), 1);
5341 object->setStringProperty("something else");
5342 QCOMPARE(object->value(), 1);
5346 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.6.qml"));
5347 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5348 QVERIFY(object != 0);
5350 // `object->value()' is the number of executed statements
5352 object->setStringProperty("A");
5353 QCOMPARE(object->value(), 123);
5355 object->setStringProperty("S");
5356 QCOMPARE(object->value(), 123);
5358 object->setStringProperty("D");
5359 QCOMPARE(object->value(), 321);
5361 object->setStringProperty("F");
5362 QCOMPARE(object->value(), 321);
5364 object->setStringProperty("something else");
5365 QCOMPARE(object->value(), 0);
5369 void tst_qdeclarativeecmascript::withStatement()
5372 QDeclarativeComponent component(&engine, TEST_FILE("withStatement.1.qml"));
5373 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5374 QVERIFY(object != 0);
5376 QCOMPARE(object->value(), 123);
5380 void tst_qdeclarativeecmascript::tryStatement()
5383 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.1.qml"));
5384 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5385 QVERIFY(object != 0);
5387 QCOMPARE(object->value(), 123);
5391 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.2.qml"));
5392 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5393 QVERIFY(object != 0);
5395 QCOMPARE(object->value(), 321);
5399 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.3.qml"));
5400 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5401 QVERIFY(object != 0);
5403 QCOMPARE(object->value(), 1);
5407 QDeclarativeComponent component(&engine, TEST_FILE("tryStatement.4.qml"));
5408 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5409 QVERIFY(object != 0);
5411 QCOMPARE(object->value(), 1);
5415 QTEST_MAIN(tst_qdeclarativeecmascript)
5417 #include "tst_qdeclarativeecmascript.moc"