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();
238 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
239 QDeclarativeEngine engine;
242 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
244 void tst_qdeclarativeecmascript::assignBasicTypes()
247 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
248 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
249 QVERIFY(object != 0);
250 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
251 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
252 QCOMPARE(object->stringProperty(), QString("Hello World!"));
253 QCOMPARE(object->uintProperty(), uint(10));
254 QCOMPARE(object->intProperty(), -19);
255 QCOMPARE((float)object->realProperty(), float(23.2));
256 QCOMPARE((float)object->doubleProperty(), float(-19.75));
257 QCOMPARE((float)object->floatProperty(), float(8.5));
258 QCOMPARE(object->colorProperty(), QColor("red"));
259 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
260 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
261 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
262 QCOMPARE(object->pointProperty(), QPoint(99,13));
263 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
264 QCOMPARE(object->sizeProperty(), QSize(99, 13));
265 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
266 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
267 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
268 QCOMPARE(object->boolProperty(), true);
269 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
270 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
271 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
275 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
276 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
277 QVERIFY(object != 0);
278 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
279 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
280 QCOMPARE(object->stringProperty(), QString("Hello World!"));
281 QCOMPARE(object->uintProperty(), uint(10));
282 QCOMPARE(object->intProperty(), -19);
283 QCOMPARE((float)object->realProperty(), float(23.2));
284 QCOMPARE((float)object->doubleProperty(), float(-19.75));
285 QCOMPARE((float)object->floatProperty(), float(8.5));
286 QCOMPARE(object->colorProperty(), QColor("red"));
287 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
288 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
289 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
290 QCOMPARE(object->pointProperty(), QPoint(99,13));
291 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
292 QCOMPARE(object->sizeProperty(), QSize(99, 13));
293 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
294 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
295 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
296 QCOMPARE(object->boolProperty(), true);
297 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
298 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
299 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
304 void tst_qdeclarativeecmascript::idShortcutInvalidates()
307 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
308 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
309 QVERIFY(object != 0);
310 QVERIFY(object->objectProperty() != 0);
311 delete object->objectProperty();
312 QVERIFY(object->objectProperty() == 0);
317 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
318 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
319 QVERIFY(object != 0);
320 QVERIFY(object->objectProperty() != 0);
321 delete object->objectProperty();
322 QVERIFY(object->objectProperty() == 0);
327 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
330 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
331 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
332 QVERIFY(object != 0);
333 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
337 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
338 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
339 QVERIFY(object != 0);
340 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
345 void tst_qdeclarativeecmascript::signalAssignment()
348 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
349 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
350 QVERIFY(object != 0);
351 QCOMPARE(object->string(), QString());
352 emit object->basicSignal();
353 QCOMPARE(object->string(), QString("pass"));
358 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
359 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
360 QVERIFY(object != 0);
361 QCOMPARE(object->string(), QString());
362 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
363 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
368 void tst_qdeclarativeecmascript::methods()
371 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
372 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
373 QVERIFY(object != 0);
374 QCOMPARE(object->methodCalled(), false);
375 QCOMPARE(object->methodIntCalled(), false);
376 emit object->basicSignal();
377 QCOMPARE(object->methodCalled(), true);
378 QCOMPARE(object->methodIntCalled(), false);
383 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
384 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
385 QVERIFY(object != 0);
386 QCOMPARE(object->methodCalled(), false);
387 QCOMPARE(object->methodIntCalled(), false);
388 emit object->basicSignal();
389 QCOMPARE(object->methodCalled(), false);
390 QCOMPARE(object->methodIntCalled(), true);
395 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
396 QObject *object = component.create();
397 QVERIFY(object != 0);
398 QCOMPARE(object->property("test").toInt(), 19);
403 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
404 QObject *object = component.create();
405 QVERIFY(object != 0);
406 QCOMPARE(object->property("test").toInt(), 19);
407 QCOMPARE(object->property("test2").toInt(), 17);
408 QCOMPARE(object->property("test3").toInt(), 16);
413 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
414 QObject *object = component.create();
415 QVERIFY(object != 0);
416 QCOMPARE(object->property("test").toInt(), 9);
421 void tst_qdeclarativeecmascript::bindingLoop()
423 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
424 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
425 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
426 QObject *object = component.create();
427 QVERIFY(object != 0);
431 void tst_qdeclarativeecmascript::basicExpressions_data()
433 QTest::addColumn<QString>("expression");
434 QTest::addColumn<QVariant>("result");
435 QTest::addColumn<bool>("nest");
437 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
438 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
439 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
440 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
441 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
442 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
443 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
444 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
445 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
446 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
447 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
448 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
449 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
450 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
451 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
452 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
453 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
454 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
455 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
458 void tst_qdeclarativeecmascript::basicExpressions()
460 QFETCH(QString, expression);
461 QFETCH(QVariant, result);
467 MyDefaultObject1 default1;
468 MyDefaultObject3 default3;
469 object1.setStringProperty("Object1");
470 object2.setStringProperty("Object2");
471 object3.setStringProperty("Object3");
473 QDeclarativeContext context(engine.rootContext());
474 QDeclarativeContext nestedContext(&context);
476 context.setContextObject(&default1);
477 context.setContextProperty("a", QVariant(1944));
478 context.setContextProperty("b", QVariant("Milk"));
479 context.setContextProperty("object", &object1);
480 context.setContextProperty("objectOverride", &object2);
481 nestedContext.setContextObject(&default3);
482 nestedContext.setContextProperty("b", QVariant("Cow"));
483 nestedContext.setContextProperty("objectOverride", &object3);
484 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
486 MyExpression expr(nest?&nestedContext:&context, expression);
487 QCOMPARE(expr.evaluate(), result);
490 void tst_qdeclarativeecmascript::arrayExpressions()
496 QDeclarativeContext context(engine.rootContext());
497 context.setContextProperty("a", &obj1);
498 context.setContextProperty("b", &obj2);
499 context.setContextProperty("c", &obj3);
501 MyExpression expr(&context, "[a, b, c, 10]");
502 QVariant result = expr.evaluate();
503 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
504 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
505 QCOMPARE(list.count(), 4);
506 QCOMPARE(list.at(0), &obj1);
507 QCOMPARE(list.at(1), &obj2);
508 QCOMPARE(list.at(2), &obj3);
509 QCOMPARE(list.at(3), (QObject *)0);
512 // Tests that modifying a context property will reevaluate expressions
513 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
515 QDeclarativeContext context(engine.rootContext());
518 MyQmlObject *object3 = new MyQmlObject;
520 object1.setStringProperty("Hello");
521 object2.setStringProperty("World");
523 context.setContextProperty("testProp", QVariant(1));
524 context.setContextProperty("testObj", &object1);
525 context.setContextProperty("testObj2", object3);
528 MyExpression expr(&context, "testProp + 1");
529 QCOMPARE(expr.changed, false);
530 QCOMPARE(expr.evaluate(), QVariant(2));
532 context.setContextProperty("testProp", QVariant(2));
533 QCOMPARE(expr.changed, true);
534 QCOMPARE(expr.evaluate(), QVariant(3));
538 MyExpression expr(&context, "testProp + testProp + testProp");
539 QCOMPARE(expr.changed, false);
540 QCOMPARE(expr.evaluate(), QVariant(6));
542 context.setContextProperty("testProp", QVariant(4));
543 QCOMPARE(expr.changed, true);
544 QCOMPARE(expr.evaluate(), QVariant(12));
548 MyExpression expr(&context, "testObj.stringProperty");
549 QCOMPARE(expr.changed, false);
550 QCOMPARE(expr.evaluate(), QVariant("Hello"));
552 context.setContextProperty("testObj", &object2);
553 QCOMPARE(expr.changed, true);
554 QCOMPARE(expr.evaluate(), QVariant("World"));
558 MyExpression expr(&context, "testObj.stringProperty /**/");
559 QCOMPARE(expr.changed, false);
560 QCOMPARE(expr.evaluate(), QVariant("World"));
562 context.setContextProperty("testObj", &object1);
563 QCOMPARE(expr.changed, true);
564 QCOMPARE(expr.evaluate(), QVariant("Hello"));
568 MyExpression expr(&context, "testObj2");
569 QCOMPARE(expr.changed, false);
570 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
576 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
578 QDeclarativeContext context(engine.rootContext());
582 context.setContextProperty("testObj", &object1);
584 object1.setStringProperty(QLatin1String("Hello"));
585 object2.setStringProperty(QLatin1String("Dog"));
586 object3.setStringProperty(QLatin1String("Cat"));
589 MyExpression expr(&context, "testObj.stringProperty");
590 QCOMPARE(expr.changed, false);
591 QCOMPARE(expr.evaluate(), QVariant("Hello"));
593 object1.setStringProperty(QLatin1String("World"));
594 QCOMPARE(expr.changed, true);
595 QCOMPARE(expr.evaluate(), QVariant("World"));
599 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
600 QCOMPARE(expr.changed, false);
601 QCOMPARE(expr.evaluate(), QVariant());
603 object1.setObjectProperty(&object2);
604 QCOMPARE(expr.changed, true);
605 expr.changed = false;
606 QCOMPARE(expr.evaluate(), QVariant("Dog"));
608 object1.setObjectProperty(&object3);
609 QCOMPARE(expr.changed, true);
610 expr.changed = false;
611 QCOMPARE(expr.evaluate(), QVariant("Cat"));
613 object1.setObjectProperty(0);
614 QCOMPARE(expr.changed, true);
615 expr.changed = false;
616 QCOMPARE(expr.evaluate(), QVariant());
618 object1.setObjectProperty(&object3);
619 QCOMPARE(expr.changed, true);
620 expr.changed = false;
621 QCOMPARE(expr.evaluate(), QVariant("Cat"));
623 object3.setStringProperty("Donkey");
624 QCOMPARE(expr.changed, true);
625 expr.changed = false;
626 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
630 void tst_qdeclarativeecmascript::deferredProperties()
632 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
633 MyDeferredObject *object =
634 qobject_cast<MyDeferredObject *>(component.create());
635 QVERIFY(object != 0);
636 QCOMPARE(object->value(), 0);
637 QVERIFY(object->objectProperty() == 0);
638 QVERIFY(object->objectProperty2() != 0);
639 qmlExecuteDeferred(object);
640 QCOMPARE(object->value(), 10);
641 QVERIFY(object->objectProperty() != 0);
642 MyQmlObject *qmlObject =
643 qobject_cast<MyQmlObject *>(object->objectProperty());
644 QVERIFY(qmlObject != 0);
645 QCOMPARE(qmlObject->value(), 10);
646 object->setValue(19);
647 QCOMPARE(qmlObject->value(), 19);
652 // Check errors on deferred properties are correctly emitted
653 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
655 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
656 MyDeferredObject *object =
657 qobject_cast<MyDeferredObject *>(component.create());
658 QVERIFY(object != 0);
659 QCOMPARE(object->value(), 0);
660 QVERIFY(object->objectProperty() == 0);
661 QVERIFY(object->objectProperty2() == 0);
663 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
664 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
666 qmlExecuteDeferred(object);
671 void tst_qdeclarativeecmascript::extensionObjects()
673 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
674 MyExtendedObject *object =
675 qobject_cast<MyExtendedObject *>(component.create());
676 QVERIFY(object != 0);
677 QCOMPARE(object->baseProperty(), 13);
678 QCOMPARE(object->coreProperty(), 9);
679 object->setProperty("extendedProperty", QVariant(11));
680 object->setProperty("baseExtendedProperty", QVariant(92));
681 QCOMPARE(object->coreProperty(), 11);
682 QCOMPARE(object->baseProperty(), 92);
684 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
686 QCOMPARE(nested->baseProperty(), 13);
687 QCOMPARE(nested->coreProperty(), 9);
688 nested->setProperty("extendedProperty", QVariant(11));
689 nested->setProperty("baseExtendedProperty", QVariant(92));
690 QCOMPARE(nested->coreProperty(), 11);
691 QCOMPARE(nested->baseProperty(), 92);
696 void tst_qdeclarativeecmascript::overrideExtensionProperties()
698 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
699 OverrideDefaultPropertyObject *object =
700 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
701 QVERIFY(object != 0);
702 QVERIFY(object->secondProperty() != 0);
703 QVERIFY(object->firstProperty() == 0);
708 void tst_qdeclarativeecmascript::attachedProperties()
711 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
712 QObject *object = component.create();
713 QVERIFY(object != 0);
714 QCOMPARE(object->property("a").toInt(), 19);
715 QCOMPARE(object->property("b").toInt(), 19);
716 QCOMPARE(object->property("c").toInt(), 19);
717 QCOMPARE(object->property("d").toInt(), 19);
722 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
723 QObject *object = component.create();
724 QVERIFY(object != 0);
725 QCOMPARE(object->property("a").toInt(), 26);
726 QCOMPARE(object->property("b").toInt(), 26);
727 QCOMPARE(object->property("c").toInt(), 26);
728 QCOMPARE(object->property("d").toInt(), 26);
734 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
735 QObject *object = component.create();
736 QVERIFY(object != 0);
738 QMetaObject::invokeMethod(object, "writeValue2");
740 MyQmlAttachedObject *attached =
741 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
742 QVERIFY(attached != 0);
744 QCOMPARE(attached->value2(), 9);
749 void tst_qdeclarativeecmascript::enums()
753 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
754 QObject *object = component.create();
755 QVERIFY(object != 0);
757 QCOMPARE(object->property("a").toInt(), 0);
758 QCOMPARE(object->property("b").toInt(), 1);
759 QCOMPARE(object->property("c").toInt(), 2);
760 QCOMPARE(object->property("d").toInt(), 3);
761 QCOMPARE(object->property("e").toInt(), 0);
762 QCOMPARE(object->property("f").toInt(), 1);
763 QCOMPARE(object->property("g").toInt(), 2);
764 QCOMPARE(object->property("h").toInt(), 3);
765 QCOMPARE(object->property("i").toInt(), 19);
766 QCOMPARE(object->property("j").toInt(), 19);
770 // Non-existent enums
772 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
774 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
775 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
776 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
777 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
779 QObject *object = component.create();
780 QVERIFY(object != 0);
781 QCOMPARE(object->property("a").toInt(), 0);
782 QCOMPARE(object->property("b").toInt(), 0);
788 void tst_qdeclarativeecmascript::valueTypeFunctions()
790 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
791 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
793 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
794 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
800 Tests that writing a constant to a property with a binding on it disables the
803 void tst_qdeclarativeecmascript::constantsOverrideBindings()
807 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
808 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
809 QVERIFY(object != 0);
811 QCOMPARE(object->property("c2").toInt(), 0);
812 object->setProperty("c1", QVariant(9));
813 QCOMPARE(object->property("c2").toInt(), 9);
815 emit object->basicSignal();
817 QCOMPARE(object->property("c2").toInt(), 13);
818 object->setProperty("c1", QVariant(8));
819 QCOMPARE(object->property("c2").toInt(), 13);
824 // During construction
826 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
827 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
828 QVERIFY(object != 0);
830 QCOMPARE(object->property("c1").toInt(), 0);
831 QCOMPARE(object->property("c2").toInt(), 10);
832 object->setProperty("c1", QVariant(9));
833 QCOMPARE(object->property("c1").toInt(), 9);
834 QCOMPARE(object->property("c2").toInt(), 10);
842 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
843 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
844 QVERIFY(object != 0);
846 QCOMPARE(object->property("c2").toInt(), 0);
847 object->setProperty("c1", QVariant(9));
848 QCOMPARE(object->property("c2").toInt(), 9);
850 object->setProperty("c2", QVariant(13));
851 QCOMPARE(object->property("c2").toInt(), 13);
852 object->setProperty("c1", QVariant(7));
853 QCOMPARE(object->property("c1").toInt(), 7);
854 QCOMPARE(object->property("c2").toInt(), 13);
862 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
863 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
864 QVERIFY(object != 0);
866 QCOMPARE(object->property("c1").toInt(), 0);
867 QCOMPARE(object->property("c3").toInt(), 10);
868 object->setProperty("c1", QVariant(9));
869 QCOMPARE(object->property("c1").toInt(), 9);
870 QCOMPARE(object->property("c3").toInt(), 10);
877 Tests that assigning a binding to a property that already has a binding causes
878 the original binding to be disabled.
880 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
882 QDeclarativeComponent component(&engine,
883 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
884 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
885 QVERIFY(object != 0);
887 QCOMPARE(object->property("c1").toInt(), 0);
888 QCOMPARE(object->property("c2").toInt(), 0);
889 QCOMPARE(object->property("c3").toInt(), 0);
891 object->setProperty("c1", QVariant(9));
892 QCOMPARE(object->property("c1").toInt(), 9);
893 QCOMPARE(object->property("c2").toInt(), 0);
894 QCOMPARE(object->property("c3").toInt(), 0);
896 object->setProperty("c3", QVariant(8));
897 QCOMPARE(object->property("c1").toInt(), 9);
898 QCOMPARE(object->property("c2").toInt(), 8);
899 QCOMPARE(object->property("c3").toInt(), 8);
905 Access a non-existent attached object.
907 Tests for a regression where this used to crash.
909 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
911 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
913 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
914 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
916 QObject *object = component.create();
917 QVERIFY(object != 0);
922 void tst_qdeclarativeecmascript::scope()
925 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
926 QObject *object = component.create();
927 QVERIFY(object != 0);
929 QCOMPARE(object->property("test1").toInt(), 1);
930 QCOMPARE(object->property("test2").toInt(), 2);
931 QCOMPARE(object->property("test3").toString(), QString("1Test"));
932 QCOMPARE(object->property("test4").toString(), QString("2Test"));
933 QCOMPARE(object->property("test5").toInt(), 1);
934 QCOMPARE(object->property("test6").toInt(), 1);
935 QCOMPARE(object->property("test7").toInt(), 2);
936 QCOMPARE(object->property("test8").toInt(), 2);
937 QCOMPARE(object->property("test9").toInt(), 1);
938 QCOMPARE(object->property("test10").toInt(), 3);
944 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
945 QObject *object = component.create();
946 QVERIFY(object != 0);
948 QCOMPARE(object->property("test1").toInt(), 19);
949 QCOMPARE(object->property("test2").toInt(), 19);
950 QCOMPARE(object->property("test3").toInt(), 14);
951 QCOMPARE(object->property("test4").toInt(), 14);
952 QCOMPARE(object->property("test5").toInt(), 24);
953 QCOMPARE(object->property("test6").toInt(), 24);
959 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
960 QObject *object = component.create();
961 QVERIFY(object != 0);
963 QCOMPARE(object->property("test1").toBool(), true);
964 QCOMPARE(object->property("test2").toBool(), true);
965 QCOMPARE(object->property("test3").toBool(), true);
970 // Signal argument scope
972 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
973 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
974 QVERIFY(object != 0);
976 QCOMPARE(object->property("test").toInt(), 0);
977 QCOMPARE(object->property("test2").toString(), QString());
979 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
981 QCOMPARE(object->property("test").toInt(), 13);
982 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
988 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
989 QObject *object = component.create();
990 QVERIFY(object != 0);
992 QCOMPARE(object->property("test1").toBool(), true);
993 QCOMPARE(object->property("test2").toBool(), true);
999 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
1000 QObject *object = component.create();
1001 QVERIFY(object != 0);
1003 QCOMPARE(object->property("test").toBool(), true);
1009 // In 4.7, non-library javascript files that had no imports shared the imports of their
1010 // importing context
1011 void tst_qdeclarativeecmascript::importScope()
1013 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1014 QObject *o = component.create();
1017 QCOMPARE(o->property("test").toInt(), 240);
1023 Tests that "any" type passes through a synthesized signal parameter. This
1024 is essentially a test of QDeclarativeMetaType::copy()
1026 void tst_qdeclarativeecmascript::signalParameterTypes()
1028 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1029 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1030 QVERIFY(object != 0);
1032 emit object->basicSignal();
1034 QCOMPARE(object->property("intProperty").toInt(), 10);
1035 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1036 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1037 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1038 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1039 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1045 Test that two JS objects for the same QObject compare as equal.
1047 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1049 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1050 QObject *object = component.create();
1051 QVERIFY(object != 0);
1053 QCOMPARE(object->property("test1").toBool(), true);
1054 QCOMPARE(object->property("test2").toBool(), true);
1055 QCOMPARE(object->property("test3").toBool(), true);
1056 QCOMPARE(object->property("test4").toBool(), true);
1057 QCOMPARE(object->property("test5").toBool(), true);
1063 Confirm bindings and alias properties can coexist.
1065 Tests for a regression where the binding would not reevaluate.
1067 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1069 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1070 QObject *object = component.create();
1071 QVERIFY(object != 0);
1073 QCOMPARE(object->property("c2").toInt(), 3);
1074 QCOMPARE(object->property("c3").toInt(), 3);
1076 object->setProperty("c2", QVariant(19));
1078 QCOMPARE(object->property("c2").toInt(), 19);
1079 QCOMPARE(object->property("c3").toInt(), 19);
1085 Ensure that we can write undefined value to an alias property,
1086 and that the aliased property is reset correctly if possible.
1088 void tst_qdeclarativeecmascript::aliasPropertyReset()
1090 QObject *object = 0;
1092 // test that a manual write (of undefined) to a resettable aliased property succeeds
1093 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1094 object = c1.create();
1095 QVERIFY(object != 0);
1096 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1097 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1098 QMetaObject::invokeMethod(object, "resetAliased");
1099 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1100 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1103 // test that a manual write (of undefined) to a resettable alias property succeeds
1104 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1105 object = c2.create();
1106 QVERIFY(object != 0);
1107 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1108 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1109 QMetaObject::invokeMethod(object, "resetAlias");
1110 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1111 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1114 // test that an alias to a bound property works correctly
1115 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1116 object = c3.create();
1117 QVERIFY(object != 0);
1118 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1119 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1120 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1121 QMetaObject::invokeMethod(object, "resetAlias");
1122 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1123 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1124 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1127 // test that a manual write (of undefined) to a resettable alias property
1128 // whose aliased property's object has been deleted, does not crash.
1129 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1130 object = c4.create();
1131 QVERIFY(object != 0);
1132 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1133 QObject *loader = object->findChild<QObject*>("loader");
1134 QVERIFY(loader != 0);
1136 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1137 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1138 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1139 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1140 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1143 // test that binding an alias property to an undefined value works correctly
1144 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1145 object = c5.create();
1146 QVERIFY(object != 0);
1147 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1150 // test that a manual write (of undefined) to a non-resettable property fails properly
1151 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1152 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1153 QDeclarativeComponent e1(&engine, url);
1154 object = e1.create();
1155 QVERIFY(object != 0);
1156 QCOMPARE(object->property("intAlias").value<int>(), 12);
1157 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1158 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1159 QMetaObject::invokeMethod(object, "resetAlias");
1160 QCOMPARE(object->property("intAlias").value<int>(), 12);
1161 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1165 void tst_qdeclarativeecmascript::dynamicCreation_data()
1167 QTest::addColumn<QString>("method");
1168 QTest::addColumn<QString>("createdName");
1170 QTest::newRow("One") << "createOne" << "objectOne";
1171 QTest::newRow("Two") << "createTwo" << "objectTwo";
1172 QTest::newRow("Three") << "createThree" << "objectThree";
1176 Test using createQmlObject to dynamically generate an item
1177 Also using createComponent is tested.
1179 void tst_qdeclarativeecmascript::dynamicCreation()
1181 QFETCH(QString, method);
1182 QFETCH(QString, createdName);
1184 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1185 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1186 QVERIFY(object != 0);
1188 QMetaObject::invokeMethod(object, method.toUtf8());
1189 QObject *created = object->objectProperty();
1191 QCOMPARE(created->objectName(), createdName);
1197 Tests the destroy function
1199 void tst_qdeclarativeecmascript::dynamicDestruction()
1202 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1203 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1204 QVERIFY(object != 0);
1205 QDeclarativeGuard<QObject> createdQmlObject = 0;
1207 QMetaObject::invokeMethod(object, "create");
1208 createdQmlObject = object->objectProperty();
1209 QVERIFY(createdQmlObject);
1210 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1212 QMetaObject::invokeMethod(object, "killOther");
1213 QVERIFY(createdQmlObject);
1214 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1215 QVERIFY(createdQmlObject);
1216 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1217 if (createdQmlObject) {
1219 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1222 QVERIFY(!createdQmlObject);
1224 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1225 QMetaObject::invokeMethod(object, "killMe");
1228 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1233 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1234 QObject *o = component.create();
1237 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1239 QMetaObject::invokeMethod(o, "create");
1241 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1243 QMetaObject::invokeMethod(o, "destroy");
1245 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1247 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1254 tests that id.toString() works
1256 void tst_qdeclarativeecmascript::objectToString()
1258 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1259 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1260 QVERIFY(object != 0);
1261 QMetaObject::invokeMethod(object, "testToString");
1262 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1263 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1269 tests that id.hasOwnProperty() works
1271 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1273 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1274 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1275 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1276 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1278 QDeclarativeComponent component(&engine, url);
1279 QObject *object = component.create();
1280 QVERIFY(object != 0);
1282 // test QObjects in QML
1283 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1284 QVERIFY(object->property("result").value<bool>() == true);
1285 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1286 QVERIFY(object->property("result").value<bool>() == false);
1288 // now test other types in QML
1289 QObject *child = object->findChild<QObject*>("typeObj");
1290 QVERIFY(child != 0);
1291 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1292 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1293 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1294 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1295 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1296 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1297 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1298 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1299 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1300 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1301 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1302 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1304 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1305 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1306 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1307 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1308 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1309 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1310 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1311 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1312 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1318 Tests bindings that indirectly cause their own deletion work.
1320 This test is best run under valgrind to ensure no invalid memory access occur.
1322 void tst_qdeclarativeecmascript::selfDeletingBinding()
1325 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1326 QObject *object = component.create();
1327 QVERIFY(object != 0);
1328 object->setProperty("triggerDelete", true);
1333 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1334 QObject *object = component.create();
1335 QVERIFY(object != 0);
1336 object->setProperty("triggerDelete", true);
1342 Test that extended object properties can be accessed.
1344 This test a regression where this used to crash. The issue was specificially
1345 for extended objects that did not include a synthesized meta object (so non-root
1346 and no synthesiszed properties).
1348 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1350 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1351 QObject *object = component.create();
1352 QVERIFY(object != 0);
1357 Test file/lineNumbers for binding/Script errors.
1359 void tst_qdeclarativeecmascript::scriptErrors()
1361 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1362 QString url = component.url().toString();
1364 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1365 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1366 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1367 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1368 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1369 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1370 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1371 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1373 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1374 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1375 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1376 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1377 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1378 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1379 QVERIFY(object != 0);
1381 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1382 emit object->basicSignal();
1384 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1385 emit object->anotherBasicSignal();
1387 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1388 emit object->thirdBasicSignal();
1394 Test file/lineNumbers for inline functions.
1396 void tst_qdeclarativeecmascript::functionErrors()
1398 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1399 QString url = component.url().toString();
1401 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1403 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1405 QObject *object = component.create();
1406 QVERIFY(object != 0);
1409 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1410 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1411 url = componentTwo.url().toString();
1412 object = componentTwo.create();
1413 QVERIFY(object != 0);
1415 QString srpname = object->property("srp_name").toString();
1417 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1418 QLatin1String(" is not a function");
1419 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1420 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1425 Test various errors that can occur when assigning a property from script
1427 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1429 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1431 QString url = component.url().toString();
1433 QObject *object = component.create();
1434 QVERIFY(object != 0);
1436 QCOMPARE(object->property("test1").toBool(), true);
1437 QCOMPARE(object->property("test2").toBool(), true);
1443 Test bindings still work when the reeval is triggered from within
1446 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1448 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1449 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1450 QVERIFY(object != 0);
1452 QCOMPARE(object->property("base").toReal(), 50.);
1453 QCOMPARE(object->property("test1").toReal(), 50.);
1454 QCOMPARE(object->property("test2").toReal(), 50.);
1456 object->basicSignal();
1458 QCOMPARE(object->property("base").toReal(), 200.);
1459 QCOMPARE(object->property("test1").toReal(), 200.);
1460 QCOMPARE(object->property("test2").toReal(), 200.);
1462 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1464 QCOMPARE(object->property("base").toReal(), 400.);
1465 QCOMPARE(object->property("test1").toReal(), 400.);
1466 QCOMPARE(object->property("test2").toReal(), 400.);
1472 Test that list properties can be iterated from ECMAScript
1474 void tst_qdeclarativeecmascript::listProperties()
1476 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1477 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1478 QVERIFY(object != 0);
1480 QCOMPARE(object->property("test1").toInt(), 21);
1481 QCOMPARE(object->property("test2").toInt(), 2);
1482 QCOMPARE(object->property("test3").toBool(), true);
1483 QCOMPARE(object->property("test4").toBool(), true);
1488 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1490 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1491 QString url = component.url().toString();
1493 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1495 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1496 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1497 QVERIFY(object != 0);
1499 QCOMPARE(object->property("test").toBool(), false);
1501 MyQmlObject object2;
1502 MyQmlObject object3;
1503 object2.setObjectProperty(&object3);
1504 object->setObjectProperty(&object2);
1506 QCOMPARE(object->property("test").toBool(), true);
1511 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1513 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1514 QString url = component.url().toString();
1516 QString warning = component.url().toString() + ":6: Error: JS exception";
1518 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1519 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1520 QVERIFY(object != 0);
1524 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1526 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1527 QString url = component.url().toString();
1529 QString warning = component.url().toString() + ":5: Error: JS exception";
1531 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1532 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1533 QVERIFY(object != 0);
1537 static int transientErrorsMsgCount = 0;
1538 static void transientErrorsMsgHandler(QtMsgType, const char *)
1540 ++transientErrorsMsgCount;
1543 // Check that transient binding errors are not displayed
1544 void tst_qdeclarativeecmascript::transientErrors()
1547 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1549 transientErrorsMsgCount = 0;
1550 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1552 QObject *object = component.create();
1553 QVERIFY(object != 0);
1555 qInstallMsgHandler(old);
1557 QCOMPARE(transientErrorsMsgCount, 0);
1562 // One binding erroring multiple times, but then resolving
1564 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1566 transientErrorsMsgCount = 0;
1567 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1569 QObject *object = component.create();
1570 QVERIFY(object != 0);
1572 qInstallMsgHandler(old);
1574 QCOMPARE(transientErrorsMsgCount, 0);
1580 // Check that errors during shutdown are minimized
1581 void tst_qdeclarativeecmascript::shutdownErrors()
1583 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1584 QObject *object = component.create();
1585 QVERIFY(object != 0);
1587 transientErrorsMsgCount = 0;
1588 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1592 qInstallMsgHandler(old);
1593 QCOMPARE(transientErrorsMsgCount, 0);
1596 void tst_qdeclarativeecmascript::compositePropertyType()
1598 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1600 QTest::ignoreMessage(QtDebugMsg, "hello world");
1601 QObject *object = qobject_cast<QObject *>(component.create());
1606 void tst_qdeclarativeecmascript::jsObject()
1608 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1609 QObject *object = component.create();
1610 QVERIFY(object != 0);
1612 QCOMPARE(object->property("test").toInt(), 92);
1617 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1620 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1621 QObject *object = component.create();
1622 QVERIFY(object != 0);
1624 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1626 object->setProperty("setUndefined", true);
1628 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1630 object->setProperty("setUndefined", false);
1632 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1637 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1638 QObject *object = component.create();
1639 QVERIFY(object != 0);
1641 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1643 QMetaObject::invokeMethod(object, "doReset");
1645 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1651 // Aliases to variant properties should work
1652 void tst_qdeclarativeecmascript::qtbug_22464()
1654 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1655 QObject *object = component.create();
1656 QVERIFY(object != 0);
1658 QCOMPARE(object->property("test").toBool(), true);
1663 void tst_qdeclarativeecmascript::qtbug_21580()
1665 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
1667 QObject *object = component.create();
1668 QVERIFY(object != 0);
1670 QCOMPARE(object->property("test").toBool(), true);
1676 void tst_qdeclarativeecmascript::bug1()
1678 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1679 QObject *object = component.create();
1680 QVERIFY(object != 0);
1682 QCOMPARE(object->property("test").toInt(), 14);
1684 object->setProperty("a", 11);
1686 QCOMPARE(object->property("test").toInt(), 3);
1688 object->setProperty("b", true);
1690 QCOMPARE(object->property("test").toInt(), 9);
1695 void tst_qdeclarativeecmascript::bug2()
1697 QDeclarativeComponent component(&engine);
1698 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1700 QObject *object = component.create();
1701 QVERIFY(object != 0);
1706 // Don't crash in createObject when the component has errors.
1707 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1709 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1710 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1711 QVERIFY(object != 0);
1713 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1714 QMetaObject::invokeMethod(object, "dontCrash");
1715 QObject *created = object->objectProperty();
1716 QVERIFY(created == 0);
1721 // ownership transferred to JS, ensure that GC runs the dtor
1722 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1725 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1727 // allow the engine to go out of scope too.
1729 QDeclarativeEngine dcoEngine;
1730 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1731 QObject *object = component.create();
1732 QVERIFY(object != 0);
1733 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1734 QVERIFY(mdcdo != 0);
1735 mdcdo->setDtorCount(&dtorCount);
1737 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1738 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1740 // we do this once manually, but it should be done automatically
1741 // when the engine goes out of scope (since it should gc in dtor)
1742 QMetaObject::invokeMethod(object, "performGc");
1745 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1751 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1752 QCOMPARE(dtorCount, expectedDtorCount);
1756 void tst_qdeclarativeecmascript::regExpBug()
1758 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1759 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1760 QVERIFY(object != 0);
1761 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1765 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1767 QString functionSource = QLatin1String("(function(object) { return ") +
1768 QLatin1String(source) + QLatin1String(" })");
1770 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1773 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1774 if (function.IsEmpty())
1776 v8::Handle<v8::Value> args[] = { o };
1777 function->Call(engine->global(), 1, args);
1778 return tc.HasCaught();
1781 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1782 const char *source, v8::Handle<v8::Value> result)
1784 QString functionSource = QLatin1String("(function(object) { return ") +
1785 QLatin1String(source) + QLatin1String(" })");
1787 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1790 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1791 if (function.IsEmpty())
1793 v8::Handle<v8::Value> args[] = { o };
1795 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1800 return value->StrictEquals(result);
1803 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1806 QString functionSource = QLatin1String("(function(object) { return ") +
1807 QLatin1String(source) + QLatin1String(" })");
1809 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1811 return v8::Handle<v8::Value>();
1812 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1813 if (function.IsEmpty())
1814 return v8::Handle<v8::Value>();
1815 v8::Handle<v8::Value> args[] = { o };
1817 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1820 return v8::Handle<v8::Value>();
1824 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1825 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1826 #define EVALUATE(source) evaluate(engine, object, source)
1828 void tst_qdeclarativeecmascript::callQtInvokables()
1830 MyInvokableObject o;
1832 QDeclarativeEngine qmlengine;
1833 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1835 QV8Engine *engine = ep->v8engine();
1837 v8::HandleScope handle_scope;
1838 v8::Context::Scope scope(engine->context());
1840 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1842 // Non-existent methods
1844 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1845 QCOMPARE(o.error(), false);
1846 QCOMPARE(o.invoked(), -1);
1847 QCOMPARE(o.actuals().count(), 0);
1850 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1851 QCOMPARE(o.error(), false);
1852 QCOMPARE(o.invoked(), -1);
1853 QCOMPARE(o.actuals().count(), 0);
1855 // Insufficient arguments
1857 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1858 QCOMPARE(o.error(), false);
1859 QCOMPARE(o.invoked(), -1);
1860 QCOMPARE(o.actuals().count(), 0);
1863 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1864 QCOMPARE(o.error(), false);
1865 QCOMPARE(o.invoked(), -1);
1866 QCOMPARE(o.actuals().count(), 0);
1868 // Excessive arguments
1870 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1871 QCOMPARE(o.error(), false);
1872 QCOMPARE(o.invoked(), 8);
1873 QCOMPARE(o.actuals().count(), 1);
1874 QCOMPARE(o.actuals().at(0), QVariant(10));
1877 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1878 QCOMPARE(o.error(), false);
1879 QCOMPARE(o.invoked(), 9);
1880 QCOMPARE(o.actuals().count(), 2);
1881 QCOMPARE(o.actuals().at(0), QVariant(10));
1882 QCOMPARE(o.actuals().at(1), QVariant(11));
1884 // Test return types
1886 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1887 QCOMPARE(o.error(), false);
1888 QCOMPARE(o.invoked(), 0);
1889 QCOMPARE(o.actuals().count(), 0);
1892 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1893 QCOMPARE(o.error(), false);
1894 QCOMPARE(o.invoked(), 1);
1895 QCOMPARE(o.actuals().count(), 0);
1898 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1899 QCOMPARE(o.error(), false);
1900 QCOMPARE(o.invoked(), 2);
1901 QCOMPARE(o.actuals().count(), 0);
1905 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1906 QVERIFY(!ret.IsEmpty());
1907 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1908 QCOMPARE(o.error(), false);
1909 QCOMPARE(o.invoked(), 3);
1910 QCOMPARE(o.actuals().count(), 0);
1915 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1916 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1917 QCOMPARE(o.error(), false);
1918 QCOMPARE(o.invoked(), 4);
1919 QCOMPARE(o.actuals().count(), 0);
1923 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1924 QCOMPARE(o.error(), false);
1925 QCOMPARE(o.invoked(), 5);
1926 QCOMPARE(o.actuals().count(), 0);
1930 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1931 QVERIFY(ret->IsString());
1932 QCOMPARE(engine->toString(ret), QString("Hello world"));
1933 QCOMPARE(o.error(), false);
1934 QCOMPARE(o.invoked(), 6);
1935 QCOMPARE(o.actuals().count(), 0);
1939 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1940 QCOMPARE(o.error(), false);
1941 QCOMPARE(o.invoked(), 7);
1942 QCOMPARE(o.actuals().count(), 0);
1946 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1947 QCOMPARE(o.error(), false);
1948 QCOMPARE(o.invoked(), 8);
1949 QCOMPARE(o.actuals().count(), 1);
1950 QCOMPARE(o.actuals().at(0), QVariant(94));
1953 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1954 QCOMPARE(o.error(), false);
1955 QCOMPARE(o.invoked(), 8);
1956 QCOMPARE(o.actuals().count(), 1);
1957 QCOMPARE(o.actuals().at(0), QVariant(94));
1960 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1961 QCOMPARE(o.error(), false);
1962 QCOMPARE(o.invoked(), 8);
1963 QCOMPARE(o.actuals().count(), 1);
1964 QCOMPARE(o.actuals().at(0), QVariant(0));
1967 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1968 QCOMPARE(o.error(), false);
1969 QCOMPARE(o.invoked(), 8);
1970 QCOMPARE(o.actuals().count(), 1);
1971 QCOMPARE(o.actuals().at(0), QVariant(0));
1974 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1975 QCOMPARE(o.error(), false);
1976 QCOMPARE(o.invoked(), 8);
1977 QCOMPARE(o.actuals().count(), 1);
1978 QCOMPARE(o.actuals().at(0), QVariant(0));
1981 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1982 QCOMPARE(o.error(), false);
1983 QCOMPARE(o.invoked(), 8);
1984 QCOMPARE(o.actuals().count(), 1);
1985 QCOMPARE(o.actuals().at(0), QVariant(0));
1988 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1989 QCOMPARE(o.error(), false);
1990 QCOMPARE(o.invoked(), 9);
1991 QCOMPARE(o.actuals().count(), 2);
1992 QCOMPARE(o.actuals().at(0), QVariant(122));
1993 QCOMPARE(o.actuals().at(1), QVariant(9));
1996 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1997 QCOMPARE(o.error(), false);
1998 QCOMPARE(o.invoked(), 10);
1999 QCOMPARE(o.actuals().count(), 1);
2000 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2003 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2004 QCOMPARE(o.error(), false);
2005 QCOMPARE(o.invoked(), 10);
2006 QCOMPARE(o.actuals().count(), 1);
2007 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2010 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2011 QCOMPARE(o.error(), false);
2012 QCOMPARE(o.invoked(), 10);
2013 QCOMPARE(o.actuals().count(), 1);
2014 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2017 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2018 QCOMPARE(o.error(), false);
2019 QCOMPARE(o.invoked(), 10);
2020 QCOMPARE(o.actuals().count(), 1);
2021 QCOMPARE(o.actuals().at(0), QVariant(0));
2024 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2025 QCOMPARE(o.error(), false);
2026 QCOMPARE(o.invoked(), 10);
2027 QCOMPARE(o.actuals().count(), 1);
2028 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2031 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2032 QCOMPARE(o.error(), false);
2033 QCOMPARE(o.invoked(), 10);
2034 QCOMPARE(o.actuals().count(), 1);
2035 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2038 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2039 QCOMPARE(o.error(), false);
2040 QCOMPARE(o.invoked(), 11);
2041 QCOMPARE(o.actuals().count(), 1);
2042 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2045 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2046 QCOMPARE(o.error(), false);
2047 QCOMPARE(o.invoked(), 11);
2048 QCOMPARE(o.actuals().count(), 1);
2049 QCOMPARE(o.actuals().at(0), QVariant("19"));
2053 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2054 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2055 QCOMPARE(o.error(), false);
2056 QCOMPARE(o.invoked(), 11);
2057 QCOMPARE(o.actuals().count(), 1);
2058 QCOMPARE(o.actuals().at(0), QVariant(expected));
2062 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2063 QCOMPARE(o.error(), false);
2064 QCOMPARE(o.invoked(), 11);
2065 QCOMPARE(o.actuals().count(), 1);
2066 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2069 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2070 QCOMPARE(o.error(), false);
2071 QCOMPARE(o.invoked(), 11);
2072 QCOMPARE(o.actuals().count(), 1);
2073 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2076 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2077 QCOMPARE(o.error(), false);
2078 QCOMPARE(o.invoked(), 12);
2079 QCOMPARE(o.actuals().count(), 1);
2080 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2083 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2084 QCOMPARE(o.error(), false);
2085 QCOMPARE(o.invoked(), 12);
2086 QCOMPARE(o.actuals().count(), 1);
2087 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2090 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2091 QCOMPARE(o.error(), false);
2092 QCOMPARE(o.invoked(), 12);
2093 QCOMPARE(o.actuals().count(), 1);
2094 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2097 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2098 QCOMPARE(o.error(), false);
2099 QCOMPARE(o.invoked(), 12);
2100 QCOMPARE(o.actuals().count(), 1);
2101 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2104 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2105 QCOMPARE(o.error(), false);
2106 QCOMPARE(o.invoked(), 12);
2107 QCOMPARE(o.actuals().count(), 1);
2108 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2111 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2112 QCOMPARE(o.error(), false);
2113 QCOMPARE(o.invoked(), 12);
2114 QCOMPARE(o.actuals().count(), 1);
2115 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2118 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2119 QCOMPARE(o.error(), false);
2120 QCOMPARE(o.invoked(), 13);
2121 QCOMPARE(o.actuals().count(), 1);
2122 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2125 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2126 QCOMPARE(o.error(), false);
2127 QCOMPARE(o.invoked(), 13);
2128 QCOMPARE(o.actuals().count(), 1);
2129 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2132 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2133 QCOMPARE(o.error(), false);
2134 QCOMPARE(o.invoked(), 13);
2135 QCOMPARE(o.actuals().count(), 1);
2136 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2139 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2140 QCOMPARE(o.error(), false);
2141 QCOMPARE(o.invoked(), 13);
2142 QCOMPARE(o.actuals().count(), 1);
2143 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2146 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2147 QCOMPARE(o.error(), false);
2148 QCOMPARE(o.invoked(), 13);
2149 QCOMPARE(o.actuals().count(), 1);
2150 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2153 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2154 QCOMPARE(o.error(), false);
2155 QCOMPARE(o.invoked(), 14);
2156 QCOMPARE(o.actuals().count(), 1);
2157 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2160 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2161 QCOMPARE(o.error(), false);
2162 QCOMPARE(o.invoked(), 14);
2163 QCOMPARE(o.actuals().count(), 1);
2164 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2167 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2168 QCOMPARE(o.error(), false);
2169 QCOMPARE(o.invoked(), 14);
2170 QCOMPARE(o.actuals().count(), 1);
2171 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2174 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2175 QCOMPARE(o.error(), false);
2176 QCOMPARE(o.invoked(), 14);
2177 QCOMPARE(o.actuals().count(), 1);
2178 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2181 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2182 QCOMPARE(o.error(), false);
2183 QCOMPARE(o.invoked(), 15);
2184 QCOMPARE(o.actuals().count(), 2);
2185 QCOMPARE(o.actuals().at(0), QVariant(4));
2186 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2189 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2190 QCOMPARE(o.error(), false);
2191 QCOMPARE(o.invoked(), 15);
2192 QCOMPARE(o.actuals().count(), 2);
2193 QCOMPARE(o.actuals().at(0), QVariant(8));
2194 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2197 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2198 QCOMPARE(o.error(), false);
2199 QCOMPARE(o.invoked(), 15);
2200 QCOMPARE(o.actuals().count(), 2);
2201 QCOMPARE(o.actuals().at(0), QVariant(3));
2202 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2205 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2206 QCOMPARE(o.error(), false);
2207 QCOMPARE(o.invoked(), 15);
2208 QCOMPARE(o.actuals().count(), 2);
2209 QCOMPARE(o.actuals().at(0), QVariant(44));
2210 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2213 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2214 QCOMPARE(o.error(), false);
2215 QCOMPARE(o.invoked(), -1);
2216 QCOMPARE(o.actuals().count(), 0);
2219 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2220 QCOMPARE(o.error(), false);
2221 QCOMPARE(o.invoked(), 16);
2222 QCOMPARE(o.actuals().count(), 1);
2223 QCOMPARE(o.actuals().at(0), QVariant(10));
2226 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2227 QCOMPARE(o.error(), false);
2228 QCOMPARE(o.invoked(), 17);
2229 QCOMPARE(o.actuals().count(), 2);
2230 QCOMPARE(o.actuals().at(0), QVariant(10));
2231 QCOMPARE(o.actuals().at(1), QVariant(11));
2234 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2235 QCOMPARE(o.error(), false);
2236 QCOMPARE(o.invoked(), 18);
2237 QCOMPARE(o.actuals().count(), 1);
2238 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2241 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2242 QCOMPARE(o.error(), false);
2243 QCOMPARE(o.invoked(), 19);
2244 QCOMPARE(o.actuals().count(), 1);
2245 QCOMPARE(o.actuals().at(0), QVariant(9));
2248 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2249 QCOMPARE(o.error(), false);
2250 QCOMPARE(o.invoked(), 20);
2251 QCOMPARE(o.actuals().count(), 2);
2252 QCOMPARE(o.actuals().at(0), QVariant(10));
2253 QCOMPARE(o.actuals().at(1), QVariant(19));
2256 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2257 QCOMPARE(o.error(), false);
2258 QCOMPARE(o.invoked(), 20);
2259 QCOMPARE(o.actuals().count(), 2);
2260 QCOMPARE(o.actuals().at(0), QVariant(10));
2261 QCOMPARE(o.actuals().at(1), QVariant(13));
2264 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2265 QCOMPARE(o.error(), false);
2266 QCOMPARE(o.invoked(), -3);
2267 QCOMPARE(o.actuals().count(), 1);
2268 QCOMPARE(o.actuals().at(0), QVariant(9));
2271 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2272 QCOMPARE(o.error(), false);
2273 QCOMPARE(o.invoked(), 21);
2274 QCOMPARE(o.actuals().count(), 2);
2275 QCOMPARE(o.actuals().at(0), QVariant(9));
2276 QCOMPARE(o.actuals().at(1), QVariant());
2279 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2280 QCOMPARE(o.error(), false);
2281 QCOMPARE(o.invoked(), 21);
2282 QCOMPARE(o.actuals().count(), 2);
2283 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2284 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2287 // QTBUG-13047 (check that you can pass registered object types as args)
2288 void tst_qdeclarativeecmascript::invokableObjectArg()
2290 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2292 QObject *o = component.create();
2294 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2296 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2301 // QTBUG-13047 (check that you can return registered object types from methods)
2302 void tst_qdeclarativeecmascript::invokableObjectRet()
2304 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2306 QObject *o = component.create();
2308 QCOMPARE(o->property("test").toBool(), true);
2313 void tst_qdeclarativeecmascript::listToVariant()
2315 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2317 MyQmlContainer container;
2319 QDeclarativeContext context(engine.rootContext());
2320 context.setContextObject(&container);
2322 QObject *object = component.create(&context);
2323 QVERIFY(object != 0);
2325 QVariant v = object->property("test");
2326 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2327 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2333 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2334 void tst_qdeclarativeecmascript::listAssignment()
2336 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2337 QObject *obj = component.create();
2338 QCOMPARE(obj->property("list1length").toInt(), 2);
2339 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2340 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2341 QCOMPARE(list1.count(&list1), list2.count(&list2));
2342 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2343 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2348 void tst_qdeclarativeecmascript::multiEngineObject()
2351 obj.setStringProperty("Howdy planet");
2353 QDeclarativeEngine e1;
2354 e1.rootContext()->setContextProperty("thing", &obj);
2355 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2357 QDeclarativeEngine e2;
2358 e2.rootContext()->setContextProperty("thing", &obj);
2359 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2361 QObject *o1 = c1.create();
2362 QObject *o2 = c2.create();
2364 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2365 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2371 // Test that references to QObjects are cleanup when the object is destroyed
2372 void tst_qdeclarativeecmascript::deletedObject()
2374 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2376 QObject *object = component.create();
2378 QCOMPARE(object->property("test1").toBool(), true);
2379 QCOMPARE(object->property("test2").toBool(), true);
2380 QCOMPARE(object->property("test3").toBool(), true);
2381 QCOMPARE(object->property("test4").toBool(), true);
2386 void tst_qdeclarativeecmascript::attachedPropertyScope()
2388 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2390 QObject *object = component.create();
2391 QVERIFY(object != 0);
2393 MyQmlAttachedObject *attached =
2394 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2395 QVERIFY(attached != 0);
2397 QCOMPARE(object->property("value2").toInt(), 0);
2399 attached->emitMySignal();
2401 QCOMPARE(object->property("value2").toInt(), 9);
2406 void tst_qdeclarativeecmascript::scriptConnect()
2409 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2411 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2412 QVERIFY(object != 0);
2414 QCOMPARE(object->property("test").toBool(), false);
2415 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2416 QCOMPARE(object->property("test").toBool(), true);
2422 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2424 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2425 QVERIFY(object != 0);
2427 QCOMPARE(object->property("test").toBool(), false);
2428 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2429 QCOMPARE(object->property("test").toBool(), true);
2435 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2437 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2438 QVERIFY(object != 0);
2440 QCOMPARE(object->property("test").toBool(), false);
2441 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2442 QCOMPARE(object->property("test").toBool(), true);
2448 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2450 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2451 QVERIFY(object != 0);
2453 QCOMPARE(object->methodCalled(), false);
2454 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2455 QCOMPARE(object->methodCalled(), true);
2461 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2463 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2464 QVERIFY(object != 0);
2466 QCOMPARE(object->methodCalled(), false);
2467 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2468 QCOMPARE(object->methodCalled(), true);
2474 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2476 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2477 QVERIFY(object != 0);
2479 QCOMPARE(object->property("test").toInt(), 0);
2480 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2481 QCOMPARE(object->property("test").toInt(), 2);
2487 void tst_qdeclarativeecmascript::scriptDisconnect()
2490 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2492 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2493 QVERIFY(object != 0);
2495 QCOMPARE(object->property("test").toInt(), 0);
2496 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2497 QCOMPARE(object->property("test").toInt(), 1);
2498 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2499 QCOMPARE(object->property("test").toInt(), 2);
2500 emit object->basicSignal();
2501 QCOMPARE(object->property("test").toInt(), 2);
2502 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2503 QCOMPARE(object->property("test").toInt(), 2);
2509 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2511 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2512 QVERIFY(object != 0);
2514 QCOMPARE(object->property("test").toInt(), 0);
2515 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2516 QCOMPARE(object->property("test").toInt(), 1);
2517 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2518 QCOMPARE(object->property("test").toInt(), 2);
2519 emit object->basicSignal();
2520 QCOMPARE(object->property("test").toInt(), 2);
2521 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2522 QCOMPARE(object->property("test").toInt(), 2);
2528 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2530 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2531 QVERIFY(object != 0);
2533 QCOMPARE(object->property("test").toInt(), 0);
2534 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2535 QCOMPARE(object->property("test").toInt(), 1);
2536 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2537 QCOMPARE(object->property("test").toInt(), 2);
2538 emit object->basicSignal();
2539 QCOMPARE(object->property("test").toInt(), 2);
2540 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2541 QCOMPARE(object->property("test").toInt(), 3);
2546 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2548 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2549 QVERIFY(object != 0);
2551 QCOMPARE(object->property("test").toInt(), 0);
2552 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2553 QCOMPARE(object->property("test").toInt(), 1);
2554 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2555 QCOMPARE(object->property("test").toInt(), 2);
2556 emit object->basicSignal();
2557 QCOMPARE(object->property("test").toInt(), 2);
2558 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2559 QCOMPARE(object->property("test").toInt(), 3);
2565 class OwnershipObject : public QObject
2569 OwnershipObject() { object = new QObject; }
2571 QPointer<QObject> object;
2574 QObject *getObject() { return object; }
2577 void tst_qdeclarativeecmascript::ownership()
2579 OwnershipObject own;
2580 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2581 context->setContextObject(&own);
2584 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2586 QVERIFY(own.object != 0);
2588 QObject *object = component.create(context);
2590 engine.collectGarbage();
2592 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2594 QVERIFY(own.object == 0);
2599 own.object = new QObject(&own);
2602 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2604 QVERIFY(own.object != 0);
2606 QObject *object = component.create(context);
2608 engine.collectGarbage();
2610 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2612 QVERIFY(own.object != 0);
2620 class CppOwnershipReturnValue : public QObject
2624 CppOwnershipReturnValue() : value(0) {}
2625 ~CppOwnershipReturnValue() { delete value; }
2627 Q_INVOKABLE QObject *create() {
2628 value = new QObject;
2629 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2633 Q_INVOKABLE MyQmlObject *createQmlObject() {
2634 MyQmlObject *rv = new MyQmlObject;
2639 QPointer<QObject> value;
2643 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2644 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2646 CppOwnershipReturnValue source;
2649 QDeclarativeEngine engine;
2650 engine.rootContext()->setContextProperty("source", &source);
2652 QVERIFY(source.value == 0);
2654 QDeclarativeComponent component(&engine);
2655 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2657 QObject *object = component.create();
2659 QVERIFY(object != 0);
2660 QVERIFY(source.value != 0);
2665 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2667 QVERIFY(source.value != 0);
2671 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2673 CppOwnershipReturnValue source;
2676 QDeclarativeEngine engine;
2677 engine.rootContext()->setContextProperty("source", &source);
2679 QVERIFY(source.value == 0);
2681 QDeclarativeComponent component(&engine);
2682 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2684 QObject *object = component.create();
2686 QVERIFY(object != 0);
2687 QVERIFY(source.value != 0);
2692 engine.collectGarbage();
2693 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2695 QVERIFY(source.value == 0);
2698 class QListQObjectMethodsObject : public QObject
2702 QListQObjectMethodsObject() {
2703 m_objects.append(new MyQmlObject());
2704 m_objects.append(new MyQmlObject());
2707 ~QListQObjectMethodsObject() {
2708 qDeleteAll(m_objects);
2712 QList<QObject *> getObjects() { return m_objects; }
2715 QList<QObject *> m_objects;
2718 // Tests that returning a QList<QObject*> from a method works
2719 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2721 QListQObjectMethodsObject obj;
2722 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2723 context->setContextObject(&obj);
2725 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2727 QObject *object = component.create(context);
2729 QCOMPARE(object->property("test").toInt(), 2);
2730 QCOMPARE(object->property("test2").toBool(), true);
2737 void tst_qdeclarativeecmascript::strictlyEquals()
2739 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2741 QObject *object = component.create();
2742 QVERIFY(object != 0);
2744 QCOMPARE(object->property("test1").toBool(), true);
2745 QCOMPARE(object->property("test2").toBool(), true);
2746 QCOMPARE(object->property("test3").toBool(), true);
2747 QCOMPARE(object->property("test4").toBool(), true);
2748 QCOMPARE(object->property("test5").toBool(), true);
2749 QCOMPARE(object->property("test6").toBool(), true);
2750 QCOMPARE(object->property("test7").toBool(), true);
2751 QCOMPARE(object->property("test8").toBool(), true);
2756 void tst_qdeclarativeecmascript::compiled()
2758 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2760 QObject *object = component.create();
2761 QVERIFY(object != 0);
2763 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2764 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2765 QCOMPARE(object->property("test3").toBool(), true);
2766 QCOMPARE(object->property("test4").toBool(), false);
2767 QCOMPARE(object->property("test5").toBool(), false);
2768 QCOMPARE(object->property("test6").toBool(), true);
2770 QCOMPARE(object->property("test7").toInt(), 185);
2771 QCOMPARE(object->property("test8").toInt(), 167);
2772 QCOMPARE(object->property("test9").toBool(), true);
2773 QCOMPARE(object->property("test10").toBool(), false);
2774 QCOMPARE(object->property("test11").toBool(), false);
2775 QCOMPARE(object->property("test12").toBool(), true);
2777 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2778 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2779 QCOMPARE(object->property("test15").toBool(), false);
2780 QCOMPARE(object->property("test16").toBool(), true);
2782 QCOMPARE(object->property("test17").toInt(), 5);
2783 QCOMPARE(object->property("test18").toReal(), qreal(176));
2784 QCOMPARE(object->property("test19").toInt(), 7);
2785 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2786 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2787 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2788 QCOMPARE(object->property("test23").toBool(), true);
2789 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2790 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2795 // Test that numbers assigned in bindings as strings work consistently
2796 void tst_qdeclarativeecmascript::numberAssignment()
2798 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2800 QObject *object = component.create();
2801 QVERIFY(object != 0);
2803 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2804 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2805 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2806 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2807 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2809 QCOMPARE(object->property("test5"), QVariant((int)7));
2810 QCOMPARE(object->property("test6"), QVariant((int)7));
2811 QCOMPARE(object->property("test7"), QVariant((int)6));
2812 QCOMPARE(object->property("test8"), QVariant((int)6));
2814 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2815 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2816 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2817 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2822 void tst_qdeclarativeecmascript::propertySplicing()
2824 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2826 QObject *object = component.create();
2827 QVERIFY(object != 0);
2829 QCOMPARE(object->property("test").toBool(), true);
2835 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2837 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2839 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2840 QVERIFY(object != 0);
2842 MyQmlObject::MyType type;
2843 type.value = 0x8971123;
2844 emit object->signalWithUnknownType(type);
2846 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2848 QCOMPARE(result.value, type.value);
2854 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2856 QTest::addColumn<QString>("expression");
2857 QTest::addColumn<QString>("compare");
2859 QString compareStrict("(function(a, b) { return a === b; })");
2860 QTest::newRow("true") << "true" << compareStrict;
2861 QTest::newRow("undefined") << "undefined" << compareStrict;
2862 QTest::newRow("null") << "null" << compareStrict;
2863 QTest::newRow("123") << "123" << compareStrict;
2864 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2866 QString comparePropertiesStrict(
2868 " if (typeof b != 'object')"
2870 " var props = Object.getOwnPropertyNames(b);"
2871 " for (var i = 0; i < props.length; ++i) {"
2872 " var p = props[i];"
2873 " return arguments.callee(a[p], b[p]);"
2876 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2877 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2880 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2882 QFETCH(QString, expression);
2883 QFETCH(QString, compare);
2885 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2886 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2887 QVERIFY(object != 0);
2889 QJSValue value = engine.evaluate(expression);
2890 QVERIFY(!engine.hasUncaughtException());
2891 object->setProperty("expression", expression);
2892 object->setProperty("compare", compare);
2893 object->setProperty("pass", false);
2895 emit object->signalWithVariant(QVariant::fromValue(value));
2896 QVERIFY(object->property("pass").toBool());
2899 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2901 signalWithJSValueInVariant_data();
2904 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2906 QFETCH(QString, expression);
2907 QFETCH(QString, compare);
2909 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2910 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2911 QVERIFY(object != 0);
2914 QJSValue value = engine2.evaluate(expression);
2915 QVERIFY(!engine2.hasUncaughtException());
2916 object->setProperty("expression", expression);
2917 object->setProperty("compare", compare);
2918 object->setProperty("pass", false);
2920 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2921 emit object->signalWithVariant(QVariant::fromValue(value));
2922 QVERIFY(!object->property("pass").toBool());
2925 void tst_qdeclarativeecmascript::moduleApi_data()
2927 QTest::addColumn<QUrl>("testfile");
2928 QTest::addColumn<QString>("errorMessage");
2929 QTest::addColumn<QStringList>("warningMessages");
2930 QTest::addColumn<QStringList>("readProperties");
2931 QTest::addColumn<QVariantList>("readExpectedValues");
2932 QTest::addColumn<QStringList>("writeProperties");
2933 QTest::addColumn<QVariantList>("writeValues");
2934 QTest::addColumn<QStringList>("readBackProperties");
2935 QTest::addColumn<QVariantList>("readBackExpectedValues");
2937 QTest::newRow("qobject, register + read + method")
2938 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2941 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2942 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2943 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2949 QTest::newRow("script, register + read")
2950 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2953 << (QStringList() << "scriptTest")
2954 << (QVariantList() << 13)
2960 QTest::newRow("qobject, caching + read")
2961 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2964 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2965 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2971 QTest::newRow("script, caching + read")
2972 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2975 << (QStringList() << "scriptTest")
2976 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2982 QTest::newRow("qobject, writing + readonly constraints")
2983 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2985 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2986 << (QStringList() << "readOnlyProperty" << "writableProperty")
2987 << (QVariantList() << 20 << 50)
2988 << (QStringList() << "firstProperty" << "writableProperty")
2989 << (QVariantList() << 30 << 30)
2990 << (QStringList() << "readOnlyProperty" << "writableProperty")
2991 << (QVariantList() << 20 << 30);
2993 QTest::newRow("script, writing + readonly constraints")
2994 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2996 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2997 << (QStringList() << "readBack" << "unchanged")
2998 << (QVariantList() << 13 << 42)
2999 << (QStringList() << "firstProperty" << "secondProperty")
3000 << (QVariantList() << 30 << 30)
3001 << (QStringList() << "readBack" << "unchanged")
3002 << (QVariantList() << 30 << 42);
3004 QTest::newRow("qobject module API enum values in JS")
3005 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3008 << (QStringList() << "enumValue" << "enumMethod")
3009 << (QVariantList() << 42 << 30)
3015 QTest::newRow("qobject, invalid major version fail")
3016 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3017 << QString("QDeclarativeComponent: Component is not ready")
3026 QTest::newRow("qobject, invalid minor version fail")
3027 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3028 << QString("QDeclarativeComponent: Component is not ready")
3038 void tst_qdeclarativeecmascript::moduleApi()
3040 QFETCH(QUrl, testfile);
3041 QFETCH(QString, errorMessage);
3042 QFETCH(QStringList, warningMessages);
3043 QFETCH(QStringList, readProperties);
3044 QFETCH(QVariantList, readExpectedValues);
3045 QFETCH(QStringList, writeProperties);
3046 QFETCH(QVariantList, writeValues);
3047 QFETCH(QStringList, readBackProperties);
3048 QFETCH(QVariantList, readBackExpectedValues);
3050 QDeclarativeComponent component(&engine, testfile);
3052 if (!errorMessage.isEmpty())
3053 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3055 if (warningMessages.size())
3056 foreach (const QString &warning, warningMessages)
3057 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3059 QObject *object = component.create();
3060 if (!errorMessage.isEmpty()) {
3061 QVERIFY(object == 0);
3063 QVERIFY(object != 0);
3064 for (int i = 0; i < readProperties.size(); ++i)
3065 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3066 for (int i = 0; i < writeProperties.size(); ++i)
3067 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3068 for (int i = 0; i < readBackProperties.size(); ++i)
3069 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3074 void tst_qdeclarativeecmascript::importScripts_data()
3076 QTest::addColumn<QUrl>("testfile");
3077 QTest::addColumn<QString>("errorMessage");
3078 QTest::addColumn<QStringList>("warningMessages");
3079 QTest::addColumn<QStringList>("propertyNames");
3080 QTest::addColumn<QVariantList>("propertyValues");
3082 QTest::newRow("basic functionality")
3083 << TEST_FILE("jsimport/testImport.qml")
3086 << (QStringList() << QLatin1String("importedScriptStringValue")
3087 << QLatin1String("importedScriptFunctionValue")
3088 << QLatin1String("importedModuleAttachedPropertyValue")
3089 << QLatin1String("importedModuleEnumValue"))
3090 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3095 QTest::newRow("import scoping")
3096 << TEST_FILE("jsimport/testImportScoping.qml")
3099 << (QStringList() << QLatin1String("componentError"))
3100 << (QVariantList() << QVariant(5));
3102 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3103 << TEST_FILE("jsimportfail/failOne.qml")
3105 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3106 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3107 << (QVariantList() << QVariant(QString()));
3109 QTest::newRow("javascript imports in an import should be private to the import scope")
3110 << TEST_FILE("jsimportfail/failTwo.qml")
3112 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3113 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3114 << (QVariantList() << QVariant(QString()));
3116 QTest::newRow("module imports in an import should be private to the import scope")
3117 << TEST_FILE("jsimportfail/failThree.qml")
3119 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3120 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3121 << (QVariantList() << QVariant(false));
3123 QTest::newRow("typenames in an import should be private to the import scope")
3124 << TEST_FILE("jsimportfail/failFour.qml")
3126 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3127 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3128 << (QVariantList() << QVariant(0));
3130 QTest::newRow("import with imports has it's own activation scope")
3131 << TEST_FILE("jsimportfail/failFive.qml")
3133 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3134 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3135 << (QStringList() << QLatin1String("componentError"))
3136 << (QVariantList() << QVariant(0));
3138 QTest::newRow("import pragma library script")
3139 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3142 << (QStringList() << QLatin1String("testValue"))
3143 << (QVariantList() << QVariant(31));
3145 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3146 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3149 << (QStringList() << QLatin1String("testValue"))
3150 << (QVariantList() << QVariant(0));
3152 QTest::newRow("import pragma library script which has an import")
3153 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3156 << (QStringList() << QLatin1String("testValue"))
3157 << (QVariantList() << QVariant(55));
3159 QTest::newRow("import pragma library script which has a pragma library import")
3160 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3163 << (QStringList() << QLatin1String("testValue"))
3164 << (QVariantList() << QVariant(18));
3167 void tst_qdeclarativeecmascript::importScripts()
3169 QFETCH(QUrl, testfile);
3170 QFETCH(QString, errorMessage);
3171 QFETCH(QStringList, warningMessages);
3172 QFETCH(QStringList, propertyNames);
3173 QFETCH(QVariantList, propertyValues);
3175 QDeclarativeComponent component(&engine, testfile);
3177 if (!errorMessage.isEmpty())
3178 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3180 if (warningMessages.size())
3181 foreach (const QString &warning, warningMessages)
3182 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3184 QObject *object = component.create();
3185 if (!errorMessage.isEmpty()) {
3186 QVERIFY(object == 0);
3188 QVERIFY(object != 0);
3189 for (int i = 0; i < propertyNames.size(); ++i)
3190 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3195 void tst_qdeclarativeecmascript::scarceResources()
3197 QPixmap origPixmap(100, 100);
3198 origPixmap.fill(Qt::blue);
3200 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3201 ScarceResourceObject *eo = 0;
3202 QObject *object = 0;
3204 // in the following three cases, the instance created from the component
3205 // has a property which is a copy of the scarce resource; hence, the
3206 // resource should NOT be detached prior to deletion of the object instance,
3207 // unless the resource is destroyed explicitly.
3208 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3209 object = component.create();
3210 QVERIFY(object != 0);
3211 QVERIFY(object->property("scarceResourceCopy").isValid());
3212 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3213 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3214 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3215 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3218 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3219 object = componentTwo.create();
3220 QVERIFY(object != 0);
3221 QVERIFY(object->property("scarceResourceCopy").isValid());
3222 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3223 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3224 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3225 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3228 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3229 object = componentThree.create();
3230 QVERIFY(object != 0);
3231 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3232 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3233 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3234 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3237 // in the following three cases, no other copy should exist in memory,
3238 // and so it should be detached (unless explicitly preserved).
3239 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3240 object = componentFour.create();
3241 QVERIFY(object != 0);
3242 QVERIFY(object->property("scarceResourceTest").isValid());
3243 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3244 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3245 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3246 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3249 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3250 object = componentFive.create();
3251 QVERIFY(object != 0);
3252 QVERIFY(object->property("scarceResourceTest").isValid());
3253 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3254 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3255 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3256 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3259 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3260 object = componentSix.create();
3261 QVERIFY(object != 0);
3262 QVERIFY(object->property("scarceResourceTest").isValid());
3263 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3264 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3265 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3266 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3269 // test that scarce resources are handled correctly for imports
3270 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3271 object = componentSeven.create();
3272 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3273 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3276 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3277 object = componentEight.create();
3278 QVERIFY(object != 0);
3279 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3280 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3283 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3284 object = componentNine.create();
3285 QVERIFY(object != 0);
3286 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3287 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3288 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3289 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3290 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3291 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3294 // test that scarce resources are handled properly in signal invocation
3295 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3296 object = componentTen.create();
3297 QVERIFY(object != 0);
3298 QObject *srsc = object->findChild<QObject*>("srsc");
3300 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3301 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3302 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3303 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3304 QMetaObject::invokeMethod(srsc, "testSignal");
3305 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3306 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3307 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3308 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3309 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3310 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3311 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3312 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3313 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3314 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3317 // test that scarce resources are handled properly from js functions in qml files
3318 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3319 object = componentEleven.create();
3320 QVERIFY(object != 0);
3321 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3322 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3323 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3324 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3325 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3326 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3327 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3328 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3329 QMetaObject::invokeMethod(object, "releaseScarceResource");
3330 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3331 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3332 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3333 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3336 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3337 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3338 object = componentTwelve.create();
3339 QVERIFY(object != 0);
3340 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3341 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3342 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3343 QString srp_name = object->property("srp_name").toString();
3344 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3345 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3346 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3347 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3348 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3349 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3350 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3354 void tst_qdeclarativeecmascript::propertyChangeSlots()
3356 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3357 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3358 QObject *object = component.create();
3359 QVERIFY(object != 0);
3362 // ensure that invalid property names fail properly.
3363 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3364 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3365 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3366 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3367 object = e1.create();
3368 QVERIFY(object == 0);
3371 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3372 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3373 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3374 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3375 object = e2.create();
3376 QVERIFY(object == 0);
3379 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3380 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3381 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3382 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3383 object = e3.create();
3384 QVERIFY(object == 0);
3387 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3388 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3389 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3390 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3391 object = e4.create();
3392 QVERIFY(object == 0);
3396 void tst_qdeclarativeecmascript::propertyVar_data()
3398 QTest::addColumn<QUrl>("qmlFile");
3401 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3402 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3403 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3404 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3405 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3406 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3407 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3408 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3409 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3412 void tst_qdeclarativeecmascript::propertyVar()
3414 QFETCH(QUrl, qmlFile);
3416 QDeclarativeComponent component(&engine, qmlFile);
3417 QObject *object = component.create();
3418 QVERIFY(object != 0);
3420 QCOMPARE(object->property("test").toBool(), true);
3425 // Tests that we can write QVariant values to var properties from C++
3426 void tst_qdeclarativeecmascript::propertyVarCpp()
3428 QObject *object = 0;
3430 // ensure that writing to and reading from a var property from cpp works as required.
3431 // Literal values stored in var properties can be read and written as QVariants
3432 // of a specific type, whereas object values are read as QVariantMaps.
3433 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3434 object = component.create();
3435 QVERIFY(object != 0);
3436 // assign int to property var that currently has int assigned
3437 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3438 QCOMPARE(object->property("varBound"), QVariant(15));
3439 QCOMPARE(object->property("intBound"), QVariant(15));
3440 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3441 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3442 // assign string to property var that current has bool assigned
3443 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3444 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3445 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3446 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3447 // now enforce behaviour when accessing JavaScript objects from cpp.
3448 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3452 static void gc(QDeclarativeEngine &engine)
3454 engine.collectGarbage();
3455 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3458 void tst_qdeclarativeecmascript::propertyVarOwnership()
3460 // Referenced JS objects are not collected
3462 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3463 QObject *object = component.create();
3464 QVERIFY(object != 0);
3465 QCOMPARE(object->property("test").toBool(), false);
3466 QMetaObject::invokeMethod(object, "runTest");
3467 QCOMPARE(object->property("test").toBool(), true);
3470 // Referenced JS objects are not collected
3472 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3473 QObject *object = component.create();
3474 QVERIFY(object != 0);
3475 QCOMPARE(object->property("test").toBool(), false);
3476 QMetaObject::invokeMethod(object, "runTest");
3477 QCOMPARE(object->property("test").toBool(), true);
3480 // Qt objects are not collected until they've been dereferenced
3482 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3483 QObject *object = component.create();
3484 QVERIFY(object != 0);
3486 QCOMPARE(object->property("test2").toBool(), false);
3487 QCOMPARE(object->property("test2").toBool(), false);
3489 QMetaObject::invokeMethod(object, "runTest");
3490 QCOMPARE(object->property("test1").toBool(), true);
3492 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3493 QVERIFY(!referencedObject.isNull());
3495 QVERIFY(!referencedObject.isNull());
3497 QMetaObject::invokeMethod(object, "runTest2");
3498 QCOMPARE(object->property("test2").toBool(), true);
3500 QVERIFY(referencedObject.isNull());
3504 // Self reference does not prevent Qt object collection
3506 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3507 QObject *object = component.create();
3508 QVERIFY(object != 0);
3510 QCOMPARE(object->property("test").toBool(), true);
3512 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3513 QVERIFY(!referencedObject.isNull());
3515 QVERIFY(!referencedObject.isNull());
3517 QMetaObject::invokeMethod(object, "runTest");
3519 QVERIFY(referencedObject.isNull());
3525 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3527 // The childObject has a reference to a different QObject. We want to ensure
3528 // that the different item will not be cleaned up until required. IE, the childObject
3529 // has implicit ownership of the constructed QObject.
3530 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3531 QObject *object = component.create();
3532 QVERIFY(object != 0);
3533 QMetaObject::invokeMethod(object, "assignCircular");
3534 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3535 QObject *rootObject = object->property("vp").value<QObject*>();
3536 QVERIFY(rootObject != 0);
3537 QObject *childObject = rootObject->findChild<QObject*>("text");
3538 QVERIFY(childObject != 0);
3539 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3540 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3541 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3542 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3543 QVERIFY(!qobjectGuard.isNull());
3544 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3545 QVERIFY(!qobjectGuard.isNull());
3546 QMetaObject::invokeMethod(object, "deassignCircular");
3547 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3548 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3552 void tst_qdeclarativeecmascript::propertyVarReparent()
3554 // ensure that nothing breaks if we re-parent objects
3555 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3556 QObject *object = component.create();
3557 QVERIFY(object != 0);
3558 QMetaObject::invokeMethod(object, "assignVarProp");
3559 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3560 QObject *rect = object->property("vp").value<QObject*>();
3561 QObject *text = rect->findChild<QObject*>("textOne");
3562 QObject *text2 = rect->findChild<QObject*>("textTwo");
3563 QWeakPointer<QObject> rectGuard(rect);
3564 QWeakPointer<QObject> textGuard(text);
3565 QWeakPointer<QObject> text2Guard(text2);
3566 QVERIFY(!rectGuard.isNull());
3567 QVERIFY(!textGuard.isNull());
3568 QVERIFY(!text2Guard.isNull());
3569 QCOMPARE(text->property("textCanary").toInt(), 11);
3570 QCOMPARE(text2->property("textCanary").toInt(), 12);
3571 // now construct an image which we will reparent.
3572 QMetaObject::invokeMethod(text2, "constructQObject");
3573 QObject *image = text2->property("vp").value<QObject*>();
3574 QWeakPointer<QObject> imageGuard(image);
3575 QVERIFY(!imageGuard.isNull());
3576 QCOMPARE(image->property("imageCanary").toInt(), 13);
3577 // now reparent the "Image" object (currently, it has JS ownership)
3578 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3579 QMetaObject::invokeMethod(text2, "deassignVp");
3580 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3581 QCOMPARE(text->property("textCanary").toInt(), 11);
3582 QCOMPARE(text2->property("textCanary").toInt(), 22);
3583 QVERIFY(!imageGuard.isNull()); // should still be alive.
3584 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3585 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3586 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3587 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3591 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3593 // sometimes reparenting can cause problems
3594 // (eg, if the ctxt is collected, varproperties are no longer available)
3595 // this test ensures that no crash occurs in that situation.
3596 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3597 QObject *object = component.create();
3598 QVERIFY(object != 0);
3599 QMetaObject::invokeMethod(object, "assignVarProp");
3600 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3601 QObject *rect = object->property("vp").value<QObject*>();
3602 QObject *text = rect->findChild<QObject*>("textOne");
3603 QObject *text2 = rect->findChild<QObject*>("textTwo");
3604 QWeakPointer<QObject> rectGuard(rect);
3605 QWeakPointer<QObject> textGuard(text);
3606 QWeakPointer<QObject> text2Guard(text2);
3607 QVERIFY(!rectGuard.isNull());
3608 QVERIFY(!textGuard.isNull());
3609 QVERIFY(!text2Guard.isNull());
3610 QCOMPARE(text->property("textCanary").toInt(), 11);
3611 QCOMPARE(text2->property("textCanary").toInt(), 12);
3612 // now construct an image which we will reparent.
3613 QMetaObject::invokeMethod(text2, "constructQObject");
3614 QObject *image = text2->property("vp").value<QObject*>();
3615 QWeakPointer<QObject> imageGuard(image);
3616 QVERIFY(!imageGuard.isNull());
3617 QCOMPARE(image->property("imageCanary").toInt(), 13);
3618 // now reparent the "Image" object (currently, it has JS ownership)
3619 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3620 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3621 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3622 QVERIFY(!imageGuard.isNull()); // should still be alive.
3623 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3625 QVERIFY(imageGuard.isNull()); // should now be dead.
3628 void tst_qdeclarativeecmascript::propertyVarCircular()
3630 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3631 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3632 QObject *object = component.create();
3633 QVERIFY(object != 0);
3634 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3635 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3636 QCOMPARE(object->property("canaryInt"), QVariant(5));
3637 QVariant canaryResourceVariant = object->property("canaryResource");
3638 QVERIFY(canaryResourceVariant.isValid());
3639 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3640 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3641 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3642 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3643 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3644 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3645 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3646 QCOMPARE(object->property("canaryInt"), QVariant(2));
3647 QCOMPARE(object->property("canaryResource"), QVariant(1));
3648 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3652 void tst_qdeclarativeecmascript::propertyVarCircular2()
3654 // track deletion of JS-owned parent item with Cpp-owned child
3655 // where the child has a var property referencing its parent.
3656 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3657 QObject *object = component.create();
3658 QVERIFY(object != 0);
3659 QMetaObject::invokeMethod(object, "assignCircular");
3660 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3661 QObject *rootObject = object->property("vp").value<QObject*>();
3662 QVERIFY(rootObject != 0);
3663 QObject *childObject = rootObject->findChild<QObject*>("text");
3664 QVERIFY(childObject != 0);
3665 QWeakPointer<QObject> rootObjectTracker(rootObject);
3666 QVERIFY(!rootObjectTracker.isNull());
3667 QWeakPointer<QObject> childObjectTracker(childObject);
3668 QVERIFY(!childObjectTracker.isNull());
3670 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3671 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3672 QMetaObject::invokeMethod(object, "deassignCircular");
3673 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3674 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3675 QVERIFY(childObjectTracker.isNull()); // should have been collected
3679 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3681 *(int*)(parameter) += 1;
3682 qPersistentDispose(object);
3685 void tst_qdeclarativeecmascript::propertyVarInheritance()
3687 int propertyVarWeakRefCallbackCount = 0;
3689 // enforce behaviour regarding element inheritance - ensure handle disposal.
3690 // The particular component under test here has a chain of references.
3691 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3692 QObject *object = component.create();
3693 QVERIFY(object != 0);
3694 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3695 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3696 // we want to be able to track when the varProperties array of the last metaobject is disposed
3697 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3698 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*>();
3699 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3700 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3701 v8::Persistent<v8::Value> icoCanaryHandle;
3702 v8::Persistent<v8::Value> ccoCanaryHandle;
3705 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3706 // public function which can return us a handle to something in the varProperties array.
3707 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3708 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3709 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3710 // as the varproperties array of each vmemo still references the resource.
3711 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3712 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3714 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3716 // now we deassign the var prop, which should trigger collection of item subtrees.
3717 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3718 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3719 // ensure that there are only weak handles to the underlying varProperties array remaining.
3721 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3723 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3724 // to what remains are weak, all varProperties arrays must have been collected.
3727 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3729 int propertyVarWeakRefCallbackCount = 0;
3731 // The particular component under test here does NOT have a chain of references; the
3732 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3733 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3734 QObject *object = component.create();
3735 QVERIFY(object != 0);
3736 QMetaObject::invokeMethod(object, "assignCircular");
3737 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3738 QObject *rootObject = object->property("vp").value<QObject*>();
3739 QVERIFY(rootObject != 0);
3740 QObject *childObject = rootObject->findChild<QObject*>("text");
3741 QVERIFY(childObject != 0);
3742 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3743 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3744 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3747 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3748 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3749 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3751 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3752 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3754 QMetaObject::invokeMethod(object, "deassignCircular");
3755 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3756 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3760 // Ensure that QObject type conversion works on binding assignment
3761 void tst_qdeclarativeecmascript::elementAssign()
3763 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3765 QObject *object = component.create();
3766 QVERIFY(object != 0);
3768 QCOMPARE(object->property("test").toBool(), true);
3774 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3776 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3778 QObject *object = component.create();
3779 QVERIFY(object != 0);
3781 QCOMPARE(object->property("test").toBool(), true);
3787 void tst_qdeclarativeecmascript::objectConversion()
3789 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3791 QObject *object = component.create();
3792 QVERIFY(object != 0);
3794 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3795 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3802 void tst_qdeclarativeecmascript::booleanConversion()
3804 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3806 QObject *object = component.create();
3807 QVERIFY(object != 0);
3809 QCOMPARE(object->property("test_true1").toBool(), true);
3810 QCOMPARE(object->property("test_true2").toBool(), true);
3811 QCOMPARE(object->property("test_true3").toBool(), true);
3812 QCOMPARE(object->property("test_true4").toBool(), true);
3813 QCOMPARE(object->property("test_true5").toBool(), true);
3815 QCOMPARE(object->property("test_false1").toBool(), false);
3816 QCOMPARE(object->property("test_false2").toBool(), false);
3817 QCOMPARE(object->property("test_false3").toBool(), false);
3822 void tst_qdeclarativeecmascript::handleReferenceManagement()
3827 // Linear QObject reference
3828 QDeclarativeEngine hrmEngine;
3829 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3830 QObject *object = component.create();
3831 QVERIFY(object != 0);
3832 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3833 cro->setDtorCount(&dtorCount);
3834 QMetaObject::invokeMethod(object, "createReference");
3836 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3838 hrmEngine.collectGarbage();
3839 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3840 QCOMPARE(dtorCount, 3);
3845 // Circular QObject reference
3846 QDeclarativeEngine hrmEngine;
3847 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3848 QObject *object = component.create();
3849 QVERIFY(object != 0);
3850 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3851 cro->setDtorCount(&dtorCount);
3852 QMetaObject::invokeMethod(object, "circularReference");
3854 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3856 hrmEngine.collectGarbage();
3857 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3858 QCOMPARE(dtorCount, 3);
3863 // Linear handle reference
3864 QDeclarativeEngine hrmEngine;
3865 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3866 QObject *object = component.create();
3867 QVERIFY(object != 0);
3868 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3870 crh->setDtorCount(&dtorCount);
3871 QMetaObject::invokeMethod(object, "createReference");
3872 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3873 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3874 QVERIFY(first != 0);
3875 QVERIFY(second != 0);
3876 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3877 // now we have to reparent second and make second owned by JS.
3878 second->setParent(0);
3879 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3881 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3883 hrmEngine.collectGarbage();
3884 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3885 QCOMPARE(dtorCount, 3);
3890 // Circular handle reference
3891 QDeclarativeEngine hrmEngine;
3892 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3893 QObject *object = component.create();
3894 QVERIFY(object != 0);
3895 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3897 crh->setDtorCount(&dtorCount);
3898 QMetaObject::invokeMethod(object, "circularReference");
3899 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3900 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3901 QVERIFY(first != 0);
3902 QVERIFY(second != 0);
3903 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3904 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3905 // now we have to reparent and change ownership.
3906 first->setParent(0);
3907 second->setParent(0);
3908 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3909 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3911 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3913 hrmEngine.collectGarbage();
3914 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3915 QCOMPARE(dtorCount, 3);
3920 // multiple engine interaction - linear reference
3921 QDeclarativeEngine hrmEngine1;
3922 QDeclarativeEngine hrmEngine2;
3923 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3924 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3925 QObject *object1 = component1.create();
3926 QObject *object2 = component2.create();
3927 QVERIFY(object1 != 0);
3928 QVERIFY(object2 != 0);
3929 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3930 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3933 crh1->setDtorCount(&dtorCount);
3934 crh2->setDtorCount(&dtorCount);
3935 QMetaObject::invokeMethod(object1, "createReference");
3936 QMetaObject::invokeMethod(object2, "createReference");
3937 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3938 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3939 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3940 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3941 QVERIFY(first1 != 0);
3942 QVERIFY(second1 != 0);
3943 QVERIFY(first2 != 0);
3944 QVERIFY(second2 != 0);
3945 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3946 // now we have to reparent second2 and make second2 owned by JS.
3947 second2->setParent(0);
3948 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3950 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3951 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3954 hrmEngine1.collectGarbage();
3955 hrmEngine2.collectGarbage();
3956 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3957 QCOMPARE(dtorCount, 6);
3962 // multiple engine interaction - circular reference
3963 QDeclarativeEngine hrmEngine1;
3964 QDeclarativeEngine hrmEngine2;
3965 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3966 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3967 QObject *object1 = component1.create();
3968 QObject *object2 = component2.create();
3969 QVERIFY(object1 != 0);
3970 QVERIFY(object2 != 0);
3971 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3972 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3975 crh1->setDtorCount(&dtorCount);
3976 crh2->setDtorCount(&dtorCount);
3977 QMetaObject::invokeMethod(object1, "createReference");
3978 QMetaObject::invokeMethod(object2, "createReference");
3979 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3980 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3981 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3982 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3983 QVERIFY(first1 != 0);
3984 QVERIFY(second1 != 0);
3985 QVERIFY(first2 != 0);
3986 QVERIFY(second2 != 0);
3987 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3988 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3989 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3990 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3991 // now we have to reparent and change ownership to JS.
3992 first1->setParent(0);
3993 second1->setParent(0);
3994 first2->setParent(0);
3995 second2->setParent(0);
3996 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3997 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3998 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3999 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4001 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4002 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4005 hrmEngine1.collectGarbage();
4006 hrmEngine2.collectGarbage();
4007 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4008 QCOMPARE(dtorCount, 6);
4013 // multiple engine interaction - linear reference with engine deletion
4014 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4015 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4016 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4017 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4018 QObject *object1 = component1.create();
4019 QObject *object2 = component2.create();
4020 QVERIFY(object1 != 0);
4021 QVERIFY(object2 != 0);
4022 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4023 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4026 crh1->setDtorCount(&dtorCount);
4027 crh2->setDtorCount(&dtorCount);
4028 QMetaObject::invokeMethod(object1, "createReference");
4029 QMetaObject::invokeMethod(object2, "createReference");
4030 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4031 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4032 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4033 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4034 QVERIFY(first1 != 0);
4035 QVERIFY(second1 != 0);
4036 QVERIFY(first2 != 0);
4037 QVERIFY(second2 != 0);
4038 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4039 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4040 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4041 // now we have to reparent and change ownership to JS.
4042 first1->setParent(crh1);
4043 second1->setParent(0);
4044 first2->setParent(0);
4045 second2->setParent(0);
4046 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4047 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4048 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4050 QCOMPARE(dtorCount, 0);
4053 QCOMPARE(dtorCount, 0);
4056 hrmEngine1->collectGarbage();
4057 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4058 QCOMPARE(dtorCount, 6);
4063 void tst_qdeclarativeecmascript::stringArg()
4065 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4066 QObject *object = component.create();
4067 QVERIFY(object != 0);
4068 QMetaObject::invokeMethod(object, "success");
4069 QVERIFY(object->property("returnValue").toBool());
4071 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4072 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4073 QMetaObject::invokeMethod(object, "failure");
4074 QVERIFY(object->property("returnValue").toBool());
4079 void tst_qdeclarativeecmascript::readonlyDeclaration()
4081 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4083 QObject *object = component.create();
4084 QVERIFY(object != 0);
4086 QCOMPARE(object->property("test").toBool(), true);
4091 Q_DECLARE_METATYPE(QList<int>)
4092 Q_DECLARE_METATYPE(QList<qreal>)
4093 Q_DECLARE_METATYPE(QList<bool>)
4094 Q_DECLARE_METATYPE(QList<QString>)
4095 Q_DECLARE_METATYPE(QList<QUrl>)
4096 void tst_qdeclarativeecmascript::sequenceConversionRead()
4099 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4100 QDeclarativeComponent component(&engine, qmlFile);
4101 QObject *object = component.create();
4102 QVERIFY(object != 0);
4103 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4106 QMetaObject::invokeMethod(object, "readSequences");
4107 QList<int> intList; intList << 1 << 2 << 3 << 4;
4108 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4109 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4110 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4111 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4112 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4113 QList<bool> boolList; boolList << true << false << true << false;
4114 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4115 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4116 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4117 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4118 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4119 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4120 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4121 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4122 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4123 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4124 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4126 QMetaObject::invokeMethod(object, "readSequenceElements");
4127 QCOMPARE(object->property("intVal").toInt(), 2);
4128 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4129 QCOMPARE(object->property("boolVal").toBool(), false);
4130 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4131 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4132 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4134 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4135 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4137 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4138 QDeclarativeProperty seqProp(seq, "intListProperty");
4139 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4140 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4141 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4143 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4144 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4150 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4151 QDeclarativeComponent component(&engine, qmlFile);
4152 QObject *object = component.create();
4153 QVERIFY(object != 0);
4154 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4157 // we haven't registered QList<QPoint> as a sequence type.
4158 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4159 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4160 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4161 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4163 QMetaObject::invokeMethod(object, "performTest");
4165 // QList<QPoint> has not been registered as a sequence type.
4166 QCOMPARE(object->property("pointListLength").toInt(), 0);
4167 QVERIFY(!object->property("pointList").isValid());
4168 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4169 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4170 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4176 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4179 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4180 QDeclarativeComponent component(&engine, qmlFile);
4181 QObject *object = component.create();
4182 QVERIFY(object != 0);
4183 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4186 QMetaObject::invokeMethod(object, "writeSequences");
4187 QCOMPARE(object->property("success").toBool(), true);
4189 QMetaObject::invokeMethod(object, "writeSequenceElements");
4190 QCOMPARE(object->property("success").toBool(), true);
4192 QMetaObject::invokeMethod(object, "writeOtherElements");
4193 QCOMPARE(object->property("success").toBool(), true);
4195 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4196 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4202 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4203 QDeclarativeComponent component(&engine, qmlFile);
4204 QObject *object = component.create();
4205 QVERIFY(object != 0);
4206 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4209 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4210 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4211 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4213 QMetaObject::invokeMethod(object, "performTest");
4215 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4216 QCOMPARE(seq->pointListProperty(), pointList);
4222 void tst_qdeclarativeecmascript::sequenceConversionArray()
4224 // ensure that in JS the returned sequences act just like normal JS Arrays.
4225 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4226 QDeclarativeComponent component(&engine, qmlFile);
4227 QObject *object = component.create();
4228 QVERIFY(object != 0);
4229 QMetaObject::invokeMethod(object, "indexedAccess");
4230 QVERIFY(object->property("success").toBool());
4231 QMetaObject::invokeMethod(object, "arrayOperations");
4232 QVERIFY(object->property("success").toBool());
4233 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4234 QVERIFY(object->property("success").toBool());
4235 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4236 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4240 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4242 // ensure that sequence conversion operations work correctly in a worker thread
4243 // and that serialisation between the main and worker thread succeeds.
4244 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4245 QDeclarativeComponent component(&engine, qmlFile);
4246 QObject *object = component.create();
4247 QVERIFY(object != 0);
4249 QMetaObject::invokeMethod(object, "testIntSequence");
4250 QTRY_VERIFY(object->property("finished").toBool());
4251 QVERIFY(object->property("success").toBool());
4253 QMetaObject::invokeMethod(object, "testQrealSequence");
4254 QTRY_VERIFY(object->property("finished").toBool());
4255 QVERIFY(object->property("success").toBool());
4257 QMetaObject::invokeMethod(object, "testBoolSequence");
4258 QTRY_VERIFY(object->property("finished").toBool());
4259 QVERIFY(object->property("success").toBool());
4261 QMetaObject::invokeMethod(object, "testStringSequence");
4262 QTRY_VERIFY(object->property("finished").toBool());
4263 QVERIFY(object->property("success").toBool());
4265 QMetaObject::invokeMethod(object, "testQStringSequence");
4266 QTRY_VERIFY(object->property("finished").toBool());
4267 QVERIFY(object->property("success").toBool());
4269 QMetaObject::invokeMethod(object, "testUrlSequence");
4270 QTRY_VERIFY(object->property("finished").toBool());
4271 QVERIFY(object->property("success").toBool());
4273 QMetaObject::invokeMethod(object, "testVariantSequence");
4274 QTRY_VERIFY(object->property("finished").toBool());
4275 QVERIFY(object->property("success").toBool());
4280 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4283 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4284 QDeclarativeComponent component(&engine, qmlFile);
4285 QObject *object = component.create();
4286 QVERIFY(object != 0);
4287 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4288 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4289 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4290 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4291 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4296 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4297 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4298 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4299 QDeclarativeComponent component(&engine, qmlFile);
4300 QObject *object = component.create();
4301 QVERIFY(object != 0);
4306 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4308 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4309 QDeclarativeComponent component(&engine, qmlFile);
4310 QObject *object = component.create();
4311 QVERIFY(object != 0);
4312 QMetaObject::invokeMethod(object, "testCopySequences");
4313 QCOMPARE(object->property("success").toBool(), true);
4314 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4315 QCOMPARE(object->property("success").toBool(), true);
4316 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4317 QCOMPARE(object->property("success").toBool(), true);
4321 // Test that assigning a null object works
4322 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4323 void tst_qdeclarativeecmascript::nullObjectBinding()
4325 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4327 QObject *object = component.create();
4328 QVERIFY(object != 0);
4330 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4335 // Test that bindings don't evaluate once the engine has been destroyed
4336 void tst_qdeclarativeecmascript::deletedEngine()
4338 QDeclarativeEngine *engine = new QDeclarativeEngine;
4339 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4341 QObject *object = component.create();
4342 QVERIFY(object != 0);
4344 QCOMPARE(object->property("a").toInt(), 39);
4345 object->setProperty("b", QVariant(9));
4346 QCOMPARE(object->property("a").toInt(), 117);
4350 QCOMPARE(object->property("a").toInt(), 117);
4351 object->setProperty("b", QVariant(10));
4352 QCOMPARE(object->property("a").toInt(), 117);
4357 // Test the crashing part of QTBUG-9705
4358 void tst_qdeclarativeecmascript::libraryScriptAssert()
4360 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4362 QObject *object = component.create();
4363 QVERIFY(object != 0);
4368 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4370 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4372 QObject *object = component.create();
4373 QVERIFY(object != 0);
4375 QCOMPARE(object->property("test1").toInt(), 10);
4376 QCOMPARE(object->property("test2").toInt(), 11);
4378 object->setProperty("runTest", true);
4380 QCOMPARE(object->property("test1"), QVariant());
4381 QCOMPARE(object->property("test2"), QVariant());
4387 void tst_qdeclarativeecmascript::qtbug_9792()
4389 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4391 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4393 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4394 QVERIFY(object != 0);
4396 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4397 object->basicSignal();
4401 transientErrorsMsgCount = 0;
4402 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4404 object->basicSignal();
4406 qInstallMsgHandler(old);
4408 QCOMPARE(transientErrorsMsgCount, 0);
4413 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4414 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4416 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4418 QObject *o = component.create();
4421 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4422 QVERIFY(nested != 0);
4424 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4427 nested = qvariant_cast<QObject *>(o->property("object"));
4428 QVERIFY(nested == 0);
4430 // If the bug is present, the next line will crash
4434 // Test that we shut down without stupid warnings
4435 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4438 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4440 QObject *o = component.create();
4442 transientErrorsMsgCount = 0;
4443 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4447 qInstallMsgHandler(old);
4449 QCOMPARE(transientErrorsMsgCount, 0);
4454 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4456 QObject *o = component.create();
4458 transientErrorsMsgCount = 0;
4459 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4463 qInstallMsgHandler(old);
4465 QCOMPARE(transientErrorsMsgCount, 0);
4469 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4472 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4474 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4477 QVERIFY(o->objectProperty() != 0);
4479 o->setProperty("runTest", true);
4481 QVERIFY(o->objectProperty() == 0);
4487 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4489 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4492 QVERIFY(o->objectProperty() == 0);
4498 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4500 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4502 QString url = component.url().toString();
4503 QString warning = url + ":4: Unable to assign a function to a property.";
4504 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4506 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4509 QVERIFY(!o->property("a").isValid());
4514 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4516 QFETCH(QString, triggerProperty);
4518 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4519 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4521 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4523 QVERIFY(!o->property("a").isValid());
4525 o->setProperty("aNumber", QVariant(5));
4526 o->setProperty(triggerProperty.toUtf8().constData(), true);
4527 QCOMPARE(o->property("a"), QVariant(50));
4529 o->setProperty("aNumber", QVariant(10));
4530 QCOMPARE(o->property("a"), QVariant(100));
4535 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4537 QTest::addColumn<QString>("triggerProperty");
4539 QTest::newRow("assign to property") << "assignToProperty";
4540 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4542 QTest::newRow("assign to value type") << "assignToValueType";
4544 QTest::newRow("use 'this'") << "assignWithThis";
4545 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4548 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4550 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4551 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4553 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4555 QVERIFY(!o->property("a").isValid());
4557 o->setProperty("assignFuncWithoutReturn", true);
4558 QVERIFY(!o->property("a").isValid());
4560 QString url = component.url().toString();
4561 QString warning = url + ":67: Unable to assign QString to int";
4562 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4563 o->setProperty("assignWrongType", true);
4565 warning = url + ":71: Unable to assign QString to int";
4566 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4567 o->setProperty("assignWrongTypeToValueType", true);
4572 void tst_qdeclarativeecmascript::eval()
4574 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4576 QObject *o = component.create();
4579 QCOMPARE(o->property("test1").toBool(), true);
4580 QCOMPARE(o->property("test2").toBool(), true);
4581 QCOMPARE(o->property("test3").toBool(), true);
4582 QCOMPARE(o->property("test4").toBool(), true);
4583 QCOMPARE(o->property("test5").toBool(), true);
4588 void tst_qdeclarativeecmascript::function()
4590 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4592 QObject *o = component.create();
4595 QCOMPARE(o->property("test1").toBool(), true);
4596 QCOMPARE(o->property("test2").toBool(), true);
4597 QCOMPARE(o->property("test3").toBool(), true);
4602 // Test the "Qt.include" method
4603 void tst_qdeclarativeecmascript::include()
4605 // Non-library relative include
4607 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4608 QObject *o = component.create();
4611 QCOMPARE(o->property("test0").toInt(), 99);
4612 QCOMPARE(o->property("test1").toBool(), true);
4613 QCOMPARE(o->property("test2").toBool(), true);
4614 QCOMPARE(o->property("test2_1").toBool(), true);
4615 QCOMPARE(o->property("test3").toBool(), true);
4616 QCOMPARE(o->property("test3_1").toBool(), true);
4621 // Library relative include
4623 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4624 QObject *o = component.create();
4627 QCOMPARE(o->property("test0").toInt(), 99);
4628 QCOMPARE(o->property("test1").toBool(), true);
4629 QCOMPARE(o->property("test2").toBool(), true);
4630 QCOMPARE(o->property("test2_1").toBool(), true);
4631 QCOMPARE(o->property("test3").toBool(), true);
4632 QCOMPARE(o->property("test3_1").toBool(), true);
4639 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4640 QObject *o = component.create();
4643 QCOMPARE(o->property("test1").toBool(), true);
4644 QCOMPARE(o->property("test2").toBool(), true);
4645 QCOMPARE(o->property("test3").toBool(), true);
4646 QCOMPARE(o->property("test4").toBool(), true);
4647 QCOMPARE(o->property("test5").toBool(), true);
4648 QCOMPARE(o->property("test6").toBool(), true);
4653 // Including file with ".pragma library"
4655 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4656 QObject *o = component.create();
4658 QCOMPARE(o->property("test1").toInt(), 100);
4665 TestHTTPServer server(8111);
4666 QVERIFY(server.isValid());
4667 server.serveDirectory(TESTDATA(""));
4669 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4670 QObject *o = component.create();
4673 QTRY_VERIFY(o->property("done").toBool() == true);
4674 QTRY_VERIFY(o->property("done2").toBool() == true);
4676 QCOMPARE(o->property("test1").toBool(), true);
4677 QCOMPARE(o->property("test2").toBool(), true);
4678 QCOMPARE(o->property("test3").toBool(), true);
4679 QCOMPARE(o->property("test4").toBool(), true);
4680 QCOMPARE(o->property("test5").toBool(), true);
4682 QCOMPARE(o->property("test6").toBool(), true);
4683 QCOMPARE(o->property("test7").toBool(), true);
4684 QCOMPARE(o->property("test8").toBool(), true);
4685 QCOMPARE(o->property("test9").toBool(), true);
4686 QCOMPARE(o->property("test10").toBool(), true);
4693 TestHTTPServer server(8111);
4694 QVERIFY(server.isValid());
4695 server.serveDirectory(TESTDATA(""));
4697 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4698 QObject *o = component.create();
4701 QTRY_VERIFY(o->property("done").toBool() == true);
4703 QCOMPARE(o->property("test1").toBool(), true);
4704 QCOMPARE(o->property("test2").toBool(), true);
4705 QCOMPARE(o->property("test3").toBool(), true);
4711 void tst_qdeclarativeecmascript::signalHandlers()
4713 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4714 QObject *o = component.create();
4717 QVERIFY(o->property("count").toInt() == 0);
4718 QMetaObject::invokeMethod(o, "testSignalCall");
4719 QCOMPARE(o->property("count").toInt(), 1);
4721 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4722 QCOMPARE(o->property("count").toInt(), 1);
4723 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4725 QVERIFY(o->property("funcCount").toInt() == 0);
4726 QMetaObject::invokeMethod(o, "testSignalConnection");
4727 QCOMPARE(o->property("funcCount").toInt(), 1);
4729 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4730 QCOMPARE(o->property("funcCount").toInt(), 2);
4732 QMetaObject::invokeMethod(o, "testSignalDefined");
4733 QCOMPARE(o->property("definedResult").toBool(), true);
4735 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4736 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4741 void tst_qdeclarativeecmascript::qtbug_10696()
4743 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4744 QObject *o = component.create();
4749 void tst_qdeclarativeecmascript::qtbug_11606()
4751 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4752 QObject *o = component.create();
4754 QCOMPARE(o->property("test").toBool(), true);
4758 void tst_qdeclarativeecmascript::qtbug_11600()
4760 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4761 QObject *o = component.create();
4763 QCOMPARE(o->property("test").toBool(), true);
4767 // Reading and writing non-scriptable properties should fail
4768 void tst_qdeclarativeecmascript::nonscriptable()
4770 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4771 QObject *o = component.create();
4773 QCOMPARE(o->property("readOk").toBool(), true);
4774 QCOMPARE(o->property("writeOk").toBool(), true);
4778 // deleteLater() should not be callable from QML
4779 void tst_qdeclarativeecmascript::deleteLater()
4781 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4782 QObject *o = component.create();
4784 QCOMPARE(o->property("test").toBool(), true);
4788 void tst_qdeclarativeecmascript::in()
4790 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4791 QObject *o = component.create();
4793 QCOMPARE(o->property("test1").toBool(), true);
4794 QCOMPARE(o->property("test2").toBool(), true);
4798 void tst_qdeclarativeecmascript::typeOf()
4800 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4801 QObject *o = component.create();
4803 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4804 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4805 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4806 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4807 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4808 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4809 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4810 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4811 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4812 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4817 void tst_qdeclarativeecmascript::sharedAttachedObject()
4819 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4820 QObject *o = component.create();
4822 QCOMPARE(o->property("test1").toBool(), true);
4823 QCOMPARE(o->property("test2").toBool(), true);
4828 void tst_qdeclarativeecmascript::objectName()
4830 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4831 QObject *o = component.create();
4834 QCOMPARE(o->property("test1").toString(), QString("hello"));
4835 QCOMPARE(o->property("test2").toString(), QString("ell"));
4837 o->setObjectName("world");
4839 QCOMPARE(o->property("test1").toString(), QString("world"));
4840 QCOMPARE(o->property("test2").toString(), QString("orl"));
4845 void tst_qdeclarativeecmascript::writeRemovesBinding()
4847 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4848 QObject *o = component.create();
4851 QCOMPARE(o->property("test").toBool(), true);
4856 // Test bindings assigned to alias properties actually assign to the alias' target
4857 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4859 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4860 QObject *o = component.create();
4863 QCOMPARE(o->property("test").toBool(), true);
4868 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4869 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4872 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4873 QObject *o = component.create();
4876 QCOMPARE(o->property("test").toBool(), true);
4882 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4883 QObject *o = component.create();
4886 QCOMPARE(o->property("test").toBool(), true);
4892 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4893 QObject *o = component.create();
4896 QCOMPARE(o->property("test").toBool(), true);
4902 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4903 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4906 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4907 QObject *o = component.create();
4910 QCOMPARE(o->property("test").toBool(), true);
4916 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4917 QObject *o = component.create();
4920 QCOMPARE(o->property("test").toBool(), true);
4926 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4927 QObject *o = component.create();
4930 QCOMPARE(o->property("test").toBool(), true);
4936 // Allow an alais to a composite element
4938 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4940 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4942 QObject *object = component.create();
4943 QVERIFY(object != 0);
4948 void tst_qdeclarativeecmascript::qtbug_20344()
4950 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
4952 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
4953 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
4955 QObject *object = component.create();
4956 QVERIFY(object != 0);
4961 void tst_qdeclarativeecmascript::revisionErrors()
4964 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4965 QString url = component.url().toString();
4967 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4968 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4969 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4971 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4972 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4973 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4974 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4975 QVERIFY(object != 0);
4979 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4980 QString url = component.url().toString();
4982 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4983 // method2, prop2 from MyRevisionedClass not available
4984 // method4, prop4 from MyRevisionedSubclass not available
4985 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4986 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4987 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4988 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4989 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4991 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4992 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4993 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4994 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4995 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4996 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4997 QVERIFY(object != 0);
5001 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5002 QString url = component.url().toString();
5004 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5005 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5006 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5007 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5008 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5009 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5010 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5011 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5012 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5013 QVERIFY(object != 0);
5018 void tst_qdeclarativeecmascript::revision()
5021 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5022 QString url = component.url().toString();
5024 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5025 QVERIFY(object != 0);
5029 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5030 QString url = component.url().toString();
5032 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5033 QVERIFY(object != 0);
5037 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5038 QString url = component.url().toString();
5040 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5041 QVERIFY(object != 0);
5044 // Test that non-root classes can resolve revisioned methods
5046 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5048 QObject *object = component.create();
5049 QVERIFY(object != 0);
5050 QCOMPARE(object->property("test").toReal(), 11.);
5055 void tst_qdeclarativeecmascript::realToInt()
5057 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5058 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5059 QVERIFY(object != 0);
5061 QMetaObject::invokeMethod(object, "test1");
5062 QCOMPARE(object->value(), int(4));
5063 QMetaObject::invokeMethod(object, "test2");
5064 QCOMPARE(object->value(), int(8));
5066 void tst_qdeclarativeecmascript::dynamicString()
5068 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5069 QObject *object = component.create();
5070 QVERIFY(object != 0);
5071 QCOMPARE(object->property("stringProperty").toString(),
5072 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5075 void tst_qdeclarativeecmascript::automaticSemicolon()
5077 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5078 QObject *object = component.create();
5079 QVERIFY(object != 0);
5082 void tst_qdeclarativeecmascript::unaryExpression()
5084 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5085 QObject *object = component.create();
5086 QVERIFY(object != 0);
5089 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5090 void tst_qdeclarativeecmascript::doubleEvaluate()
5092 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5093 QObject *object = component.create();
5094 QVERIFY(object != 0);
5095 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5097 QCOMPARE(wc->count(), 1);
5099 wc->setProperty("x", 9);
5101 QCOMPARE(wc->count(), 2);
5106 static QStringList messages;
5107 static void captureMsgHandler(QtMsgType, const char *msg)
5109 messages.append(QLatin1String(msg));
5112 void tst_qdeclarativeecmascript::nonNotifyable()
5114 QV4Compiler::enableV4(false);
5115 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5116 QV4Compiler::enableV4(true);
5118 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5120 QObject *object = component.create();
5121 qInstallMsgHandler(old);
5123 QVERIFY(object != 0);
5125 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5126 component.url().toString() +
5127 QLatin1String(":5 depends on non-NOTIFYable properties:");
5128 QString expected2 = QLatin1String(" ") +
5129 QLatin1String(object->metaObject()->className()) +
5130 QLatin1String("::value");
5132 QCOMPARE(messages.length(), 2);
5133 QCOMPARE(messages.at(0), expected1);
5134 QCOMPARE(messages.at(1), expected2);
5139 void tst_qdeclarativeecmascript::forInLoop()
5141 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5142 QObject *object = component.create();
5143 QVERIFY(object != 0);
5145 QMetaObject::invokeMethod(object, "listProperty");
5147 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5148 QCOMPARE(r.size(), 3);
5149 QCOMPARE(r[0],QLatin1String("0=obj1"));
5150 QCOMPARE(r[1],QLatin1String("1=obj2"));
5151 QCOMPARE(r[2],QLatin1String("2=obj3"));
5153 //TODO: should test for in loop for other objects (such as QObjects) as well.
5158 // An object the binding depends on is deleted while the binding is still running
5159 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5161 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5162 QObject *object = component.create();
5163 QVERIFY(object != 0);
5167 void tst_qdeclarativeecmascript::qtbug_22679()
5170 object.setStringProperty(QLatin1String("Please work correctly"));
5171 engine.rootContext()->setContextProperty("contextProp", &object);
5173 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5174 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5175 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5177 QObject *o = component.create();
5179 QCOMPARE(warningsSpy.count(), 0);
5183 void tst_qdeclarativeecmascript::qtbug_22843_data()
5185 QTest::addColumn<bool>("library");
5187 QTest::newRow("without .pragma library") << false;
5188 QTest::newRow("with .pragma library") << true;
5191 void tst_qdeclarativeecmascript::qtbug_22843()
5193 QFETCH(bool, library);
5195 QString fileName("qtbug_22843");
5197 fileName += QLatin1String(".library");
5198 fileName += QLatin1String(".qml");
5200 QDeclarativeComponent component(&engine, TEST_FILE(fileName));
5201 QString url = component.url().toString();
5202 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5203 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5205 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5206 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5207 for (int x = 0; x < 3; ++x) {
5208 warningsSpy.clear();
5209 // For libraries, only the first import attempt should produce a
5210 // SyntaxError warning; subsequent component creation should not
5211 // attempt to reload the script.
5212 bool expectSyntaxError = !library || (x == 0);
5213 if (expectSyntaxError)
5214 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5215 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5216 QObject *object = component.create();
5217 QVERIFY(object != 0);
5218 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5224 void tst_qdeclarativeecmascript::switchStatement()
5227 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.1.qml"));
5228 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5229 QVERIFY(object != 0);
5231 // `object->value()' is the number of executed statements
5233 object->setStringProperty("A");
5234 QCOMPARE(object->value(), 5);
5236 object->setStringProperty("S");
5237 QCOMPARE(object->value(), 3);
5239 object->setStringProperty("D");
5240 QCOMPARE(object->value(), 3);
5242 object->setStringProperty("F");
5243 QCOMPARE(object->value(), 4);
5245 object->setStringProperty("something else");
5246 QCOMPARE(object->value(), 1);
5250 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.2.qml"));
5251 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5252 QVERIFY(object != 0);
5254 // `object->value()' is the number of executed statements
5256 object->setStringProperty("A");
5257 QCOMPARE(object->value(), 5);
5259 object->setStringProperty("S");
5260 QCOMPARE(object->value(), 3);
5262 object->setStringProperty("D");
5263 QCOMPARE(object->value(), 3);
5265 object->setStringProperty("F");
5266 QCOMPARE(object->value(), 3);
5268 object->setStringProperty("something else");
5269 QCOMPARE(object->value(), 4);
5273 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.3.qml"));
5274 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5275 QVERIFY(object != 0);
5277 // `object->value()' is the number of executed statements
5279 object->setStringProperty("A");
5280 QCOMPARE(object->value(), 5);
5282 object->setStringProperty("S");
5283 QCOMPARE(object->value(), 3);
5285 object->setStringProperty("D");
5286 QCOMPARE(object->value(), 3);
5288 object->setStringProperty("F");
5289 QCOMPARE(object->value(), 3);
5291 object->setStringProperty("something else");
5292 QCOMPARE(object->value(), 6);
5296 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.4.qml"));
5297 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5298 QVERIFY(object != 0);
5300 // `object->value()' is the number of executed statements
5302 object->setStringProperty("A");
5303 QCOMPARE(object->value(), 5);
5305 object->setStringProperty("S");
5306 QCOMPARE(object->value(), 3);
5308 object->setStringProperty("D");
5309 QCOMPARE(object->value(), 3);
5311 object->setStringProperty("F");
5312 QCOMPARE(object->value(), 3);
5314 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5315 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5317 object->setStringProperty("something else");
5321 QDeclarativeComponent component(&engine, TEST_FILE("switchStatement.5.qml"));
5322 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5323 QVERIFY(object != 0);
5325 // `object->value()' is the number of executed statements
5327 object->setStringProperty("A");
5328 QCOMPARE(object->value(), 1);
5330 object->setStringProperty("S");
5331 QCOMPARE(object->value(), 1);
5333 object->setStringProperty("D");
5334 QCOMPARE(object->value(), 1);
5336 object->setStringProperty("F");
5337 QCOMPARE(object->value(), 1);
5339 object->setStringProperty("something else");
5340 QCOMPARE(object->value(), 1);
5344 QTEST_MAIN(tst_qdeclarativeecmascript)
5346 #include "tst_qdeclarativeecmascript.moc"