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 ****************************************************************************/
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 "testtypes.h"
53 #include "testhttpserver.h"
54 #include "../../../shared/util.h"
57 // In Symbian OS test data is located in applications private dir
62 This test covers evaluation of ECMAScript expressions and bindings from within
63 QML. This does not include static QML language issues.
65 Static QML language issues are covered in qmllanguage
67 inline QUrl TEST_FILE(const QString &filename)
69 QFileInfo fileInfo(__FILE__);
70 return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
73 inline QUrl TEST_FILE(const char *filename)
75 return TEST_FILE(QLatin1String(filename));
78 class tst_qdeclarativeecmascript : public QObject
82 tst_qdeclarativeecmascript() {}
86 void assignBasicTypes();
87 void idShortcutInvalidates();
88 void boolPropertiesEvaluateAsBool();
90 void signalAssignment();
92 void basicExpressions();
93 void basicExpressions_data();
94 void arrayExpressions();
95 void contextPropertiesTriggerReeval();
96 void objectPropertiesTriggerReeval();
97 void deferredProperties();
98 void deferredPropertiesErrors();
99 void extensionObjects();
100 void overrideExtensionProperties();
101 void attachedProperties();
103 void valueTypeFunctions();
104 void constantsOverrideBindings();
105 void outerBindingOverridesInnerBinding();
106 void aliasPropertyAndBinding();
107 void aliasPropertyReset();
108 void nonExistentAttachedObject();
111 void signalParameterTypes();
112 void objectsCompareAsEqual();
113 void dynamicCreation_data();
114 void dynamicCreation();
115 void dynamicDestruction();
116 void objectToString();
117 void objectHasOwnProperty();
118 void selfDeletingBinding();
119 void extendedObjectPropertyLookup();
121 void functionErrors();
122 void propertyAssignmentErrors();
123 void signalTriggeredBindings();
124 void listProperties();
125 void exceptionClearsOnReeval();
126 void exceptionSlotProducesWarning();
127 void exceptionBindingProducesWarning();
128 void transientErrors();
129 void shutdownErrors();
130 void compositePropertyType();
132 void undefinedResetsProperty();
133 void listToVariant();
134 void listAssignment();
135 void multiEngineObject();
136 void deletedObject();
137 void attachedPropertyScope();
138 void scriptConnect();
139 void scriptDisconnect();
141 void cppOwnershipReturnValue();
142 void ownershipCustomReturnValue();
143 void qlistqobjectMethods();
144 void strictlyEquals();
146 void numberAssignment();
147 void propertySplicing();
148 void signalWithUnknownTypes();
149 void moduleApi_data();
151 void importScripts();
152 void scarceResources();
153 void propertyChangeSlots();
154 void elementAssign();
155 void objectPassThroughSignals();
156 void booleanConversion();
157 void handleReferenceManagement();
161 void dynamicCreationCrash();
163 void nullObjectBinding();
164 void deletedEngine();
165 void libraryScriptAssert();
166 void variantsAssignedUndefined();
168 void qtcreatorbug_1289();
169 void noSpuriousWarningsAtShutdown();
170 void canAssignNullToQObject();
171 void functionAssignment_fromBinding();
172 void functionAssignment_fromJS();
173 void functionAssignment_fromJS_data();
174 void functionAssignmentfromJS_invalid();
180 void nonscriptable();
183 void sharedAttachedObject();
185 void writeRemovesBinding();
186 void aliasBindingsAssignCorrectly();
187 void aliasBindingsOverrideTarget();
188 void aliasWritesOverrideBindings();
189 void aliasToCompositeElement();
191 void dynamicString();
193 void signalHandlers();
195 void callQtInvokables();
196 void invokableObjectArg();
197 void invokableObjectRet();
199 void revisionErrors();
202 void automaticSemicolon();
205 QDeclarativeEngine engine;
208 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
210 void tst_qdeclarativeecmascript::assignBasicTypes()
213 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
214 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
215 QVERIFY(object != 0);
216 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
217 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
218 QCOMPARE(object->stringProperty(), QString("Hello World!"));
219 QCOMPARE(object->uintProperty(), uint(10));
220 QCOMPARE(object->intProperty(), -19);
221 QCOMPARE((float)object->realProperty(), float(23.2));
222 QCOMPARE((float)object->doubleProperty(), float(-19.75));
223 QCOMPARE((float)object->floatProperty(), float(8.5));
224 QCOMPARE(object->colorProperty(), QColor("red"));
225 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
226 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
227 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
228 QCOMPARE(object->pointProperty(), QPoint(99,13));
229 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
230 QCOMPARE(object->sizeProperty(), QSize(99, 13));
231 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
232 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
233 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
234 QCOMPARE(object->boolProperty(), true);
235 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
236 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
237 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
241 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
242 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
243 QVERIFY(object != 0);
244 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
245 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
246 QCOMPARE(object->stringProperty(), QString("Hello World!"));
247 QCOMPARE(object->uintProperty(), uint(10));
248 QCOMPARE(object->intProperty(), -19);
249 QCOMPARE((float)object->realProperty(), float(23.2));
250 QCOMPARE((float)object->doubleProperty(), float(-19.75));
251 QCOMPARE((float)object->floatProperty(), float(8.5));
252 QCOMPARE(object->colorProperty(), QColor("red"));
253 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
254 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
255 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
256 QCOMPARE(object->pointProperty(), QPoint(99,13));
257 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
258 QCOMPARE(object->sizeProperty(), QSize(99, 13));
259 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
260 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
261 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
262 QCOMPARE(object->boolProperty(), true);
263 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
264 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
265 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
270 void tst_qdeclarativeecmascript::idShortcutInvalidates()
273 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
274 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
275 QVERIFY(object != 0);
276 QVERIFY(object->objectProperty() != 0);
277 delete object->objectProperty();
278 QVERIFY(object->objectProperty() == 0);
283 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
284 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
285 QVERIFY(object != 0);
286 QVERIFY(object->objectProperty() != 0);
287 delete object->objectProperty();
288 QVERIFY(object->objectProperty() == 0);
293 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
296 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
297 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
298 QVERIFY(object != 0);
299 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
303 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
304 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
305 QVERIFY(object != 0);
306 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
311 void tst_qdeclarativeecmascript::signalAssignment()
314 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
315 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
316 QVERIFY(object != 0);
317 QCOMPARE(object->string(), QString());
318 emit object->basicSignal();
319 QCOMPARE(object->string(), QString("pass"));
324 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
325 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
326 QVERIFY(object != 0);
327 QCOMPARE(object->string(), QString());
328 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
329 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
334 void tst_qdeclarativeecmascript::methods()
337 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
338 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
339 QVERIFY(object != 0);
340 QCOMPARE(object->methodCalled(), false);
341 QCOMPARE(object->methodIntCalled(), false);
342 emit object->basicSignal();
343 QCOMPARE(object->methodCalled(), true);
344 QCOMPARE(object->methodIntCalled(), false);
349 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
350 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
351 QVERIFY(object != 0);
352 QCOMPARE(object->methodCalled(), false);
353 QCOMPARE(object->methodIntCalled(), false);
354 emit object->basicSignal();
355 QCOMPARE(object->methodCalled(), false);
356 QCOMPARE(object->methodIntCalled(), true);
361 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
362 QObject *object = component.create();
363 QVERIFY(object != 0);
364 QCOMPARE(object->property("test").toInt(), 19);
369 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
370 QObject *object = component.create();
371 QVERIFY(object != 0);
372 QCOMPARE(object->property("test").toInt(), 19);
373 QCOMPARE(object->property("test2").toInt(), 17);
374 QCOMPARE(object->property("test3").toInt(), 16);
379 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
380 QObject *object = component.create();
381 QVERIFY(object != 0);
382 QCOMPARE(object->property("test").toInt(), 9);
387 void tst_qdeclarativeecmascript::bindingLoop()
389 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
390 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
391 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
392 QObject *object = component.create();
393 QVERIFY(object != 0);
397 void tst_qdeclarativeecmascript::basicExpressions_data()
399 QTest::addColumn<QString>("expression");
400 QTest::addColumn<QVariant>("result");
401 QTest::addColumn<bool>("nest");
403 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
404 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
405 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
406 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
407 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
408 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
409 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
410 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
411 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
412 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
413 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
414 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
415 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
416 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
417 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
418 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
419 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
420 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
421 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
424 void tst_qdeclarativeecmascript::basicExpressions()
426 QFETCH(QString, expression);
427 QFETCH(QVariant, result);
433 MyDefaultObject1 default1;
434 MyDefaultObject3 default3;
435 object1.setStringProperty("Object1");
436 object2.setStringProperty("Object2");
437 object3.setStringProperty("Object3");
439 QDeclarativeContext context(engine.rootContext());
440 QDeclarativeContext nestedContext(&context);
442 context.setContextObject(&default1);
443 context.setContextProperty("a", QVariant(1944));
444 context.setContextProperty("b", QVariant("Milk"));
445 context.setContextProperty("object", &object1);
446 context.setContextProperty("objectOverride", &object2);
447 nestedContext.setContextObject(&default3);
448 nestedContext.setContextProperty("b", QVariant("Cow"));
449 nestedContext.setContextProperty("objectOverride", &object3);
450 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
452 MyExpression expr(nest?&nestedContext:&context, expression);
453 QCOMPARE(expr.evaluate(), result);
456 void tst_qdeclarativeecmascript::arrayExpressions()
462 QDeclarativeContext context(engine.rootContext());
463 context.setContextProperty("a", &obj1);
464 context.setContextProperty("b", &obj2);
465 context.setContextProperty("c", &obj3);
467 MyExpression expr(&context, "[a, b, c, 10]");
468 QVariant result = expr.evaluate();
469 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
470 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
471 QCOMPARE(list.count(), 4);
472 QCOMPARE(list.at(0), &obj1);
473 QCOMPARE(list.at(1), &obj2);
474 QCOMPARE(list.at(2), &obj3);
475 QCOMPARE(list.at(3), (QObject *)0);
478 // Tests that modifying a context property will reevaluate expressions
479 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
481 QDeclarativeContext context(engine.rootContext());
484 MyQmlObject *object3 = new MyQmlObject;
486 object1.setStringProperty("Hello");
487 object2.setStringProperty("World");
489 context.setContextProperty("testProp", QVariant(1));
490 context.setContextProperty("testObj", &object1);
491 context.setContextProperty("testObj2", object3);
494 MyExpression expr(&context, "testProp + 1");
495 QCOMPARE(expr.changed, false);
496 QCOMPARE(expr.evaluate(), QVariant(2));
498 context.setContextProperty("testProp", QVariant(2));
499 QCOMPARE(expr.changed, true);
500 QCOMPARE(expr.evaluate(), QVariant(3));
504 MyExpression expr(&context, "testProp + testProp + testProp");
505 QCOMPARE(expr.changed, false);
506 QCOMPARE(expr.evaluate(), QVariant(6));
508 context.setContextProperty("testProp", QVariant(4));
509 QCOMPARE(expr.changed, true);
510 QCOMPARE(expr.evaluate(), QVariant(12));
514 MyExpression expr(&context, "testObj.stringProperty");
515 QCOMPARE(expr.changed, false);
516 QCOMPARE(expr.evaluate(), QVariant("Hello"));
518 context.setContextProperty("testObj", &object2);
519 QCOMPARE(expr.changed, true);
520 QCOMPARE(expr.evaluate(), QVariant("World"));
524 MyExpression expr(&context, "testObj.stringProperty /**/");
525 QCOMPARE(expr.changed, false);
526 QCOMPARE(expr.evaluate(), QVariant("World"));
528 context.setContextProperty("testObj", &object1);
529 QCOMPARE(expr.changed, true);
530 QCOMPARE(expr.evaluate(), QVariant("Hello"));
534 MyExpression expr(&context, "testObj2");
535 QCOMPARE(expr.changed, false);
536 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
542 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
544 QDeclarativeContext context(engine.rootContext());
548 context.setContextProperty("testObj", &object1);
550 object1.setStringProperty(QLatin1String("Hello"));
551 object2.setStringProperty(QLatin1String("Dog"));
552 object3.setStringProperty(QLatin1String("Cat"));
555 MyExpression expr(&context, "testObj.stringProperty");
556 QCOMPARE(expr.changed, false);
557 QCOMPARE(expr.evaluate(), QVariant("Hello"));
559 object1.setStringProperty(QLatin1String("World"));
560 QCOMPARE(expr.changed, true);
561 QCOMPARE(expr.evaluate(), QVariant("World"));
565 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
566 QCOMPARE(expr.changed, false);
567 QCOMPARE(expr.evaluate(), QVariant());
569 object1.setObjectProperty(&object2);
570 QCOMPARE(expr.changed, true);
571 expr.changed = false;
572 QCOMPARE(expr.evaluate(), QVariant("Dog"));
574 object1.setObjectProperty(&object3);
575 QCOMPARE(expr.changed, true);
576 expr.changed = false;
577 QCOMPARE(expr.evaluate(), QVariant("Cat"));
579 object1.setObjectProperty(0);
580 QCOMPARE(expr.changed, true);
581 expr.changed = false;
582 QCOMPARE(expr.evaluate(), QVariant());
584 object1.setObjectProperty(&object3);
585 QCOMPARE(expr.changed, true);
586 expr.changed = false;
587 QCOMPARE(expr.evaluate(), QVariant("Cat"));
589 object3.setStringProperty("Donkey");
590 QCOMPARE(expr.changed, true);
591 expr.changed = false;
592 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
596 void tst_qdeclarativeecmascript::deferredProperties()
598 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
599 MyDeferredObject *object =
600 qobject_cast<MyDeferredObject *>(component.create());
601 QVERIFY(object != 0);
602 QCOMPARE(object->value(), 0);
603 QVERIFY(object->objectProperty() == 0);
604 QVERIFY(object->objectProperty2() != 0);
605 qmlExecuteDeferred(object);
606 QCOMPARE(object->value(), 10);
607 QVERIFY(object->objectProperty() != 0);
608 MyQmlObject *qmlObject =
609 qobject_cast<MyQmlObject *>(object->objectProperty());
610 QVERIFY(qmlObject != 0);
611 QCOMPARE(qmlObject->value(), 10);
612 object->setValue(19);
613 QCOMPARE(qmlObject->value(), 19);
618 // Check errors on deferred properties are correctly emitted
619 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
621 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
622 MyDeferredObject *object =
623 qobject_cast<MyDeferredObject *>(component.create());
624 QVERIFY(object != 0);
625 QCOMPARE(object->value(), 0);
626 QVERIFY(object->objectProperty() == 0);
627 QVERIFY(object->objectProperty2() == 0);
629 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
630 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
632 qmlExecuteDeferred(object);
637 void tst_qdeclarativeecmascript::extensionObjects()
639 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
640 MyExtendedObject *object =
641 qobject_cast<MyExtendedObject *>(component.create());
642 QVERIFY(object != 0);
643 QCOMPARE(object->baseProperty(), 13);
644 QCOMPARE(object->coreProperty(), 9);
645 object->setProperty("extendedProperty", QVariant(11));
646 object->setProperty("baseExtendedProperty", QVariant(92));
647 QCOMPARE(object->coreProperty(), 11);
648 QCOMPARE(object->baseProperty(), 92);
650 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
652 QCOMPARE(nested->baseProperty(), 13);
653 QCOMPARE(nested->coreProperty(), 9);
654 nested->setProperty("extendedProperty", QVariant(11));
655 nested->setProperty("baseExtendedProperty", QVariant(92));
656 QCOMPARE(nested->coreProperty(), 11);
657 QCOMPARE(nested->baseProperty(), 92);
662 void tst_qdeclarativeecmascript::overrideExtensionProperties()
664 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
665 OverrideDefaultPropertyObject *object =
666 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
667 QVERIFY(object != 0);
668 QVERIFY(object->secondProperty() != 0);
669 QVERIFY(object->firstProperty() == 0);
674 void tst_qdeclarativeecmascript::attachedProperties()
677 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
678 QObject *object = component.create();
679 QVERIFY(object != 0);
680 QCOMPARE(object->property("a").toInt(), 19);
681 QCOMPARE(object->property("b").toInt(), 19);
682 QCOMPARE(object->property("c").toInt(), 19);
683 QCOMPARE(object->property("d").toInt(), 19);
688 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
689 QObject *object = component.create();
690 QVERIFY(object != 0);
691 QCOMPARE(object->property("a").toInt(), 26);
692 QCOMPARE(object->property("b").toInt(), 26);
693 QCOMPARE(object->property("c").toInt(), 26);
694 QCOMPARE(object->property("d").toInt(), 26);
700 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
701 QObject *object = component.create();
702 QVERIFY(object != 0);
704 QMetaObject::invokeMethod(object, "writeValue2");
706 MyQmlAttachedObject *attached =
707 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
708 QVERIFY(attached != 0);
710 QCOMPARE(attached->value2(), 9);
715 void tst_qdeclarativeecmascript::enums()
719 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
720 QObject *object = component.create();
721 QVERIFY(object != 0);
723 QCOMPARE(object->property("a").toInt(), 0);
724 QCOMPARE(object->property("b").toInt(), 1);
725 QCOMPARE(object->property("c").toInt(), 2);
726 QCOMPARE(object->property("d").toInt(), 3);
727 QCOMPARE(object->property("e").toInt(), 0);
728 QCOMPARE(object->property("f").toInt(), 1);
729 QCOMPARE(object->property("g").toInt(), 2);
730 QCOMPARE(object->property("h").toInt(), 3);
731 QCOMPARE(object->property("i").toInt(), 19);
732 QCOMPARE(object->property("j").toInt(), 19);
736 // Non-existent enums
738 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
740 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
741 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
742 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
743 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
745 QObject *object = component.create();
746 QVERIFY(object != 0);
747 QCOMPARE(object->property("a").toInt(), 0);
748 QCOMPARE(object->property("b").toInt(), 0);
754 void tst_qdeclarativeecmascript::valueTypeFunctions()
756 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
757 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
759 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
760 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
766 Tests that writing a constant to a property with a binding on it disables the
769 void tst_qdeclarativeecmascript::constantsOverrideBindings()
773 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
774 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
775 QVERIFY(object != 0);
777 QCOMPARE(object->property("c2").toInt(), 0);
778 object->setProperty("c1", QVariant(9));
779 QCOMPARE(object->property("c2").toInt(), 9);
781 emit object->basicSignal();
783 QCOMPARE(object->property("c2").toInt(), 13);
784 object->setProperty("c1", QVariant(8));
785 QCOMPARE(object->property("c2").toInt(), 13);
790 // During construction
792 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
793 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
794 QVERIFY(object != 0);
796 QCOMPARE(object->property("c1").toInt(), 0);
797 QCOMPARE(object->property("c2").toInt(), 10);
798 object->setProperty("c1", QVariant(9));
799 QCOMPARE(object->property("c1").toInt(), 9);
800 QCOMPARE(object->property("c2").toInt(), 10);
808 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
809 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
810 QVERIFY(object != 0);
812 QCOMPARE(object->property("c2").toInt(), 0);
813 object->setProperty("c1", QVariant(9));
814 QCOMPARE(object->property("c2").toInt(), 9);
816 object->setProperty("c2", QVariant(13));
817 QCOMPARE(object->property("c2").toInt(), 13);
818 object->setProperty("c1", QVariant(7));
819 QCOMPARE(object->property("c1").toInt(), 7);
820 QCOMPARE(object->property("c2").toInt(), 13);
828 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
829 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
830 QVERIFY(object != 0);
832 QCOMPARE(object->property("c1").toInt(), 0);
833 QCOMPARE(object->property("c3").toInt(), 10);
834 object->setProperty("c1", QVariant(9));
835 QCOMPARE(object->property("c1").toInt(), 9);
836 QCOMPARE(object->property("c3").toInt(), 10);
843 Tests that assigning a binding to a property that already has a binding causes
844 the original binding to be disabled.
846 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
848 QDeclarativeComponent component(&engine,
849 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
850 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
851 QVERIFY(object != 0);
853 QCOMPARE(object->property("c1").toInt(), 0);
854 QCOMPARE(object->property("c2").toInt(), 0);
855 QCOMPARE(object->property("c3").toInt(), 0);
857 object->setProperty("c1", QVariant(9));
858 QCOMPARE(object->property("c1").toInt(), 9);
859 QCOMPARE(object->property("c2").toInt(), 0);
860 QCOMPARE(object->property("c3").toInt(), 0);
862 object->setProperty("c3", QVariant(8));
863 QCOMPARE(object->property("c1").toInt(), 9);
864 QCOMPARE(object->property("c2").toInt(), 8);
865 QCOMPARE(object->property("c3").toInt(), 8);
871 Access a non-existent attached object.
873 Tests for a regression where this used to crash.
875 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
877 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
879 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
880 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
882 QObject *object = component.create();
883 QVERIFY(object != 0);
888 void tst_qdeclarativeecmascript::scope()
891 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
892 QObject *object = component.create();
893 QVERIFY(object != 0);
895 QCOMPARE(object->property("test1").toInt(), 1);
896 QCOMPARE(object->property("test2").toInt(), 2);
897 QCOMPARE(object->property("test3").toString(), QString("1Test"));
898 QCOMPARE(object->property("test4").toString(), QString("2Test"));
899 QCOMPARE(object->property("test5").toInt(), 1);
900 QCOMPARE(object->property("test6").toInt(), 1);
901 QCOMPARE(object->property("test7").toInt(), 2);
902 QCOMPARE(object->property("test8").toInt(), 2);
903 QCOMPARE(object->property("test9").toInt(), 1);
904 QCOMPARE(object->property("test10").toInt(), 3);
910 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
911 QObject *object = component.create();
912 QVERIFY(object != 0);
914 QCOMPARE(object->property("test1").toInt(), 19);
915 QCOMPARE(object->property("test2").toInt(), 19);
916 QCOMPARE(object->property("test3").toInt(), 14);
917 QCOMPARE(object->property("test4").toInt(), 14);
918 QCOMPARE(object->property("test5").toInt(), 24);
919 QCOMPARE(object->property("test6").toInt(), 24);
925 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
926 QObject *object = component.create();
927 QVERIFY(object != 0);
929 QCOMPARE(object->property("test1").toBool(), true);
930 QCOMPARE(object->property("test2").toBool(), true);
931 QCOMPARE(object->property("test3").toBool(), true);
936 // Signal argument scope
938 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
939 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
940 QVERIFY(object != 0);
942 QCOMPARE(object->property("test").toInt(), 0);
943 QCOMPARE(object->property("test2").toString(), QString());
945 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
947 QCOMPARE(object->property("test").toInt(), 13);
948 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
954 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
955 QObject *object = component.create();
956 QVERIFY(object != 0);
958 QCOMPARE(object->property("test1").toBool(), true);
959 QCOMPARE(object->property("test2").toBool(), true);
965 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
966 QObject *object = component.create();
967 QVERIFY(object != 0);
969 QCOMPARE(object->property("test").toBool(), true);
975 // In 4.7, non-library javascript files that had no imports shared the imports of their
977 void tst_qdeclarativeecmascript::importScope()
979 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
980 QObject *o = component.create();
983 QCOMPARE(o->property("test").toInt(), 240);
989 Tests that "any" type passes through a synthesized signal parameter. This
990 is essentially a test of QDeclarativeMetaType::copy()
992 void tst_qdeclarativeecmascript::signalParameterTypes()
994 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
995 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
996 QVERIFY(object != 0);
998 emit object->basicSignal();
1000 QCOMPARE(object->property("intProperty").toInt(), 10);
1001 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1002 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1003 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1004 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1005 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1011 Test that two JS objects for the same QObject compare as equal.
1013 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1015 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1016 QObject *object = component.create();
1017 QVERIFY(object != 0);
1019 QCOMPARE(object->property("test1").toBool(), true);
1020 QCOMPARE(object->property("test2").toBool(), true);
1021 QCOMPARE(object->property("test3").toBool(), true);
1022 QCOMPARE(object->property("test4").toBool(), true);
1023 QCOMPARE(object->property("test5").toBool(), true);
1029 Confirm bindings and alias properties can coexist.
1031 Tests for a regression where the binding would not reevaluate.
1033 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1035 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1036 QObject *object = component.create();
1037 QVERIFY(object != 0);
1039 QCOMPARE(object->property("c2").toInt(), 3);
1040 QCOMPARE(object->property("c3").toInt(), 3);
1042 object->setProperty("c2", QVariant(19));
1044 QCOMPARE(object->property("c2").toInt(), 19);
1045 QCOMPARE(object->property("c3").toInt(), 19);
1051 Ensure that we can write undefined value to an alias property,
1052 and that the aliased property is reset correctly if possible.
1054 void tst_qdeclarativeecmascript::aliasPropertyReset()
1056 QObject *object = 0;
1058 // test that a manual write (of undefined) to a resettable aliased property succeeds
1059 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1060 object = c1.create();
1061 QVERIFY(object != 0);
1062 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1063 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1064 QMetaObject::invokeMethod(object, "resetAliased");
1065 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1066 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1069 // test that a manual write (of undefined) to a resettable alias property succeeds
1070 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1071 object = c2.create();
1072 QVERIFY(object != 0);
1073 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1074 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1075 QMetaObject::invokeMethod(object, "resetAlias");
1076 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1077 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1080 // test that an alias to a bound property works correctly
1081 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1082 object = c3.create();
1083 QVERIFY(object != 0);
1084 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1085 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1086 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1087 QMetaObject::invokeMethod(object, "resetAlias");
1088 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1089 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1090 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1093 // test that a manual write (of undefined) to a resettable alias property
1094 // whose aliased property's object has been deleted, does not crash.
1095 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1096 object = c4.create();
1097 QVERIFY(object != 0);
1098 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1099 QObject *loader = object->findChild<QObject*>("loader");
1100 QVERIFY(loader != 0);
1102 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1103 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1105 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1106 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1109 // test that binding an alias property to an undefined value works correctly
1110 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1111 object = c5.create();
1112 QVERIFY(object != 0);
1113 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1116 // test that a manual write (of undefined) to a non-resettable property fails properly
1117 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1118 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1119 QDeclarativeComponent e1(&engine, url);
1120 object = e1.create();
1121 QVERIFY(object != 0);
1122 QCOMPARE(object->property("intAlias").value<int>(), 12);
1123 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1124 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1125 QMetaObject::invokeMethod(object, "resetAlias");
1126 QCOMPARE(object->property("intAlias").value<int>(), 12);
1127 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1131 void tst_qdeclarativeecmascript::dynamicCreation_data()
1133 QTest::addColumn<QString>("method");
1134 QTest::addColumn<QString>("createdName");
1136 QTest::newRow("One") << "createOne" << "objectOne";
1137 QTest::newRow("Two") << "createTwo" << "objectTwo";
1138 QTest::newRow("Three") << "createThree" << "objectThree";
1142 Test using createQmlObject to dynamically generate an item
1143 Also using createComponent is tested.
1145 void tst_qdeclarativeecmascript::dynamicCreation()
1147 QFETCH(QString, method);
1148 QFETCH(QString, createdName);
1150 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1151 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1152 QVERIFY(object != 0);
1154 QMetaObject::invokeMethod(object, method.toUtf8());
1155 QObject *created = object->objectProperty();
1157 QCOMPARE(created->objectName(), createdName);
1163 Tests the destroy function
1165 void tst_qdeclarativeecmascript::dynamicDestruction()
1168 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1169 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1170 QVERIFY(object != 0);
1171 QDeclarativeGuard<QObject> createdQmlObject = 0;
1173 QMetaObject::invokeMethod(object, "create");
1174 createdQmlObject = object->objectProperty();
1175 QVERIFY(createdQmlObject);
1176 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1178 QMetaObject::invokeMethod(object, "killOther");
1179 QVERIFY(createdQmlObject);
1180 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1181 QVERIFY(createdQmlObject);
1182 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1183 if (createdQmlObject) {
1185 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1188 QVERIFY(!createdQmlObject);
1190 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1191 QMetaObject::invokeMethod(object, "killMe");
1194 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1199 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1200 QObject *o = component.create();
1203 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1205 QMetaObject::invokeMethod(o, "create");
1207 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1209 QMetaObject::invokeMethod(o, "destroy");
1211 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1213 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1220 tests that id.toString() works
1222 void tst_qdeclarativeecmascript::objectToString()
1224 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1225 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1226 QVERIFY(object != 0);
1227 QMetaObject::invokeMethod(object, "testToString");
1228 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1229 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1235 tests that id.hasOwnProperty() works
1237 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1239 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1240 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1241 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1242 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1244 QDeclarativeComponent component(&engine, url);
1245 QObject *object = component.create();
1246 QVERIFY(object != 0);
1248 // test QObjects in QML
1249 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1250 QVERIFY(object->property("result").value<bool>() == true);
1251 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1252 QVERIFY(object->property("result").value<bool>() == false);
1254 // now test other types in QML
1255 QObject *child = object->findChild<QObject*>("typeObj");
1256 QVERIFY(child != 0);
1257 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1258 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1259 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1260 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1261 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1262 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1263 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1264 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1265 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1266 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1267 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1268 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1270 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1271 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1272 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1273 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1274 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1275 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1276 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1277 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1278 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1284 Tests bindings that indirectly cause their own deletion work.
1286 This test is best run under valgrind to ensure no invalid memory access occur.
1288 void tst_qdeclarativeecmascript::selfDeletingBinding()
1291 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1292 QObject *object = component.create();
1293 QVERIFY(object != 0);
1294 object->setProperty("triggerDelete", true);
1299 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1300 QObject *object = component.create();
1301 QVERIFY(object != 0);
1302 object->setProperty("triggerDelete", true);
1308 Test that extended object properties can be accessed.
1310 This test a regression where this used to crash. The issue was specificially
1311 for extended objects that did not include a synthesized meta object (so non-root
1312 and no synthesiszed properties).
1314 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1316 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1317 QObject *object = component.create();
1318 QVERIFY(object != 0);
1323 Test file/lineNumbers for binding/Script errors.
1325 void tst_qdeclarativeecmascript::scriptErrors()
1327 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1328 QString url = component.url().toString();
1330 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1331 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1332 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1333 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1334 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1335 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1336 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1337 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1339 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1340 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1341 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1342 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1343 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1344 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1345 QVERIFY(object != 0);
1347 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1348 emit object->basicSignal();
1350 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1351 emit object->anotherBasicSignal();
1353 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1354 emit object->thirdBasicSignal();
1360 Test file/lineNumbers for inline functions.
1362 void tst_qdeclarativeecmascript::functionErrors()
1364 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1365 QString url = component.url().toString();
1367 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1369 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1371 QObject *object = component.create();
1372 QVERIFY(object != 0);
1375 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1376 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1377 url = componentTwo.url().toString();
1378 object = componentTwo.create();
1379 QVERIFY(object != 0);
1381 QString srpname = object->property("srp_name").toString();
1383 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1384 QLatin1String(" is not a function");
1385 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1386 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1391 Test various errors that can occur when assigning a property from script
1393 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1395 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1397 QString url = component.url().toString();
1399 QObject *object = component.create();
1400 QVERIFY(object != 0);
1402 QCOMPARE(object->property("test1").toBool(), true);
1403 QCOMPARE(object->property("test2").toBool(), true);
1409 Test bindings still work when the reeval is triggered from within
1412 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1414 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1415 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1416 QVERIFY(object != 0);
1418 QCOMPARE(object->property("base").toReal(), 50.);
1419 QCOMPARE(object->property("test1").toReal(), 50.);
1420 QCOMPARE(object->property("test2").toReal(), 50.);
1422 object->basicSignal();
1424 QCOMPARE(object->property("base").toReal(), 200.);
1425 QCOMPARE(object->property("test1").toReal(), 200.);
1426 QCOMPARE(object->property("test2").toReal(), 200.);
1428 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1430 QCOMPARE(object->property("base").toReal(), 400.);
1431 QCOMPARE(object->property("test1").toReal(), 400.);
1432 QCOMPARE(object->property("test2").toReal(), 400.);
1438 Test that list properties can be iterated from ECMAScript
1440 void tst_qdeclarativeecmascript::listProperties()
1442 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1443 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1444 QVERIFY(object != 0);
1446 QCOMPARE(object->property("test1").toInt(), 21);
1447 QCOMPARE(object->property("test2").toInt(), 2);
1448 QCOMPARE(object->property("test3").toBool(), true);
1449 QCOMPARE(object->property("test4").toBool(), true);
1454 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1456 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1457 QString url = component.url().toString();
1459 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1461 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1462 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1463 QVERIFY(object != 0);
1465 QCOMPARE(object->property("test").toBool(), false);
1467 MyQmlObject object2;
1468 MyQmlObject object3;
1469 object2.setObjectProperty(&object3);
1470 object->setObjectProperty(&object2);
1472 QCOMPARE(object->property("test").toBool(), true);
1477 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1479 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1480 QString url = component.url().toString();
1482 QString warning = component.url().toString() + ":6: Error: JS exception";
1484 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1485 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1486 QVERIFY(object != 0);
1490 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1492 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1493 QString url = component.url().toString();
1495 QString warning = component.url().toString() + ":5: Error: JS exception";
1497 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1498 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1499 QVERIFY(object != 0);
1503 static int transientErrorsMsgCount = 0;
1504 static void transientErrorsMsgHandler(QtMsgType, const char *)
1506 ++transientErrorsMsgCount;
1509 // Check that transient binding errors are not displayed
1510 void tst_qdeclarativeecmascript::transientErrors()
1513 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1515 transientErrorsMsgCount = 0;
1516 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1518 QObject *object = component.create();
1519 QVERIFY(object != 0);
1521 qInstallMsgHandler(old);
1523 QCOMPARE(transientErrorsMsgCount, 0);
1528 // One binding erroring multiple times, but then resolving
1530 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1532 transientErrorsMsgCount = 0;
1533 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1535 QObject *object = component.create();
1536 QVERIFY(object != 0);
1538 qInstallMsgHandler(old);
1540 QCOMPARE(transientErrorsMsgCount, 0);
1546 // Check that errors during shutdown are minimized
1547 void tst_qdeclarativeecmascript::shutdownErrors()
1549 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1550 QObject *object = component.create();
1551 QVERIFY(object != 0);
1553 transientErrorsMsgCount = 0;
1554 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1558 qInstallMsgHandler(old);
1559 QCOMPARE(transientErrorsMsgCount, 0);
1562 void tst_qdeclarativeecmascript::compositePropertyType()
1564 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1565 QTest::ignoreMessage(QtDebugMsg, "hello world");
1566 QObject *object = qobject_cast<QObject *>(component.create());
1571 void tst_qdeclarativeecmascript::jsObject()
1573 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1574 QObject *object = component.create();
1575 QVERIFY(object != 0);
1577 QCOMPARE(object->property("test").toInt(), 92);
1582 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1585 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1586 QObject *object = component.create();
1587 QVERIFY(object != 0);
1589 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1591 object->setProperty("setUndefined", true);
1593 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1595 object->setProperty("setUndefined", false);
1597 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1602 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1603 QObject *object = component.create();
1604 QVERIFY(object != 0);
1606 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1608 QMetaObject::invokeMethod(object, "doReset");
1610 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1617 void tst_qdeclarativeecmascript::bug1()
1619 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1620 QObject *object = component.create();
1621 QVERIFY(object != 0);
1623 QCOMPARE(object->property("test").toInt(), 14);
1625 object->setProperty("a", 11);
1627 QCOMPARE(object->property("test").toInt(), 3);
1629 object->setProperty("b", true);
1631 QCOMPARE(object->property("test").toInt(), 9);
1636 void tst_qdeclarativeecmascript::bug2()
1638 QDeclarativeComponent component(&engine);
1639 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1641 QObject *object = component.create();
1642 QVERIFY(object != 0);
1647 // Don't crash in createObject when the component has errors.
1648 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1650 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1651 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1652 QVERIFY(object != 0);
1654 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1655 QMetaObject::invokeMethod(object, "dontCrash");
1656 QObject *created = object->objectProperty();
1657 QVERIFY(created == 0);
1663 void tst_qdeclarativeecmascript::regExpBug()
1665 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1666 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1667 QVERIFY(object != 0);
1668 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1672 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1674 QString functionSource = QLatin1String("(function(object) { return ") +
1675 QLatin1String(source) + QLatin1String(" })");
1677 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1680 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1681 if (function.IsEmpty())
1683 v8::Handle<v8::Value> args[] = { o };
1684 function->Call(engine->global(), 1, args);
1685 return tc.HasCaught();
1688 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1689 const char *source, v8::Handle<v8::Value> result)
1691 QString functionSource = QLatin1String("(function(object) { return ") +
1692 QLatin1String(source) + QLatin1String(" })");
1694 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1697 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1698 if (function.IsEmpty())
1700 v8::Handle<v8::Value> args[] = { o };
1702 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1707 return value->StrictEquals(result);
1710 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1713 QString functionSource = QLatin1String("(function(object) { return ") +
1714 QLatin1String(source) + QLatin1String(" })");
1716 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1718 return v8::Handle<v8::Value>();
1719 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1720 if (function.IsEmpty())
1721 return v8::Handle<v8::Value>();
1722 v8::Handle<v8::Value> args[] = { o };
1724 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1727 return v8::Handle<v8::Value>();
1731 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1732 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1733 #define EVALUATE(source) evaluate(engine, object, source)
1735 void tst_qdeclarativeecmascript::callQtInvokables()
1737 MyInvokableObject o;
1739 QDeclarativeEngine qmlengine;
1740 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1742 QV8Engine *engine = ep->v8engine();
1744 v8::HandleScope handle_scope;
1745 v8::Context::Scope scope(engine->context());
1747 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1749 // Non-existent methods
1751 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1752 QCOMPARE(o.error(), false);
1753 QCOMPARE(o.invoked(), -1);
1754 QCOMPARE(o.actuals().count(), 0);
1757 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1758 QCOMPARE(o.error(), false);
1759 QCOMPARE(o.invoked(), -1);
1760 QCOMPARE(o.actuals().count(), 0);
1762 // Insufficient arguments
1764 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1765 QCOMPARE(o.error(), false);
1766 QCOMPARE(o.invoked(), -1);
1767 QCOMPARE(o.actuals().count(), 0);
1770 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1771 QCOMPARE(o.error(), false);
1772 QCOMPARE(o.invoked(), -1);
1773 QCOMPARE(o.actuals().count(), 0);
1775 // Excessive arguments
1777 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1778 QCOMPARE(o.error(), false);
1779 QCOMPARE(o.invoked(), 8);
1780 QCOMPARE(o.actuals().count(), 1);
1781 QCOMPARE(o.actuals().at(0), QVariant(10));
1784 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1785 QCOMPARE(o.error(), false);
1786 QCOMPARE(o.invoked(), 9);
1787 QCOMPARE(o.actuals().count(), 2);
1788 QCOMPARE(o.actuals().at(0), QVariant(10));
1789 QCOMPARE(o.actuals().at(1), QVariant(11));
1791 // Test return types
1793 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1794 QCOMPARE(o.error(), false);
1795 QCOMPARE(o.invoked(), 0);
1796 QCOMPARE(o.actuals().count(), 0);
1799 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1800 QCOMPARE(o.error(), false);
1801 QCOMPARE(o.invoked(), 1);
1802 QCOMPARE(o.actuals().count(), 0);
1805 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1806 QCOMPARE(o.error(), false);
1807 QCOMPARE(o.invoked(), 2);
1808 QCOMPARE(o.actuals().count(), 0);
1812 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1813 QVERIFY(!ret.IsEmpty());
1814 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1815 QCOMPARE(o.error(), false);
1816 QCOMPARE(o.invoked(), 3);
1817 QCOMPARE(o.actuals().count(), 0);
1822 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1823 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1824 QCOMPARE(o.error(), false);
1825 QCOMPARE(o.invoked(), 4);
1826 QCOMPARE(o.actuals().count(), 0);
1830 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1831 QCOMPARE(o.error(), false);
1832 QCOMPARE(o.invoked(), 5);
1833 QCOMPARE(o.actuals().count(), 0);
1837 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1838 QVERIFY(ret->IsString());
1839 QCOMPARE(engine->toString(ret), QString("Hello world"));
1840 QCOMPARE(o.error(), false);
1841 QCOMPARE(o.invoked(), 6);
1842 QCOMPARE(o.actuals().count(), 0);
1846 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1847 QCOMPARE(o.error(), false);
1848 QCOMPARE(o.invoked(), 7);
1849 QCOMPARE(o.actuals().count(), 0);
1853 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1854 QCOMPARE(o.error(), false);
1855 QCOMPARE(o.invoked(), 8);
1856 QCOMPARE(o.actuals().count(), 1);
1857 QCOMPARE(o.actuals().at(0), QVariant(94));
1860 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1861 QCOMPARE(o.error(), false);
1862 QCOMPARE(o.invoked(), 8);
1863 QCOMPARE(o.actuals().count(), 1);
1864 QCOMPARE(o.actuals().at(0), QVariant(94));
1867 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1868 QCOMPARE(o.error(), false);
1869 QCOMPARE(o.invoked(), 8);
1870 QCOMPARE(o.actuals().count(), 1);
1871 QCOMPARE(o.actuals().at(0), QVariant(0));
1874 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1875 QCOMPARE(o.error(), false);
1876 QCOMPARE(o.invoked(), 8);
1877 QCOMPARE(o.actuals().count(), 1);
1878 QCOMPARE(o.actuals().at(0), QVariant(0));
1881 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1882 QCOMPARE(o.error(), false);
1883 QCOMPARE(o.invoked(), 8);
1884 QCOMPARE(o.actuals().count(), 1);
1885 QCOMPARE(o.actuals().at(0), QVariant(0));
1888 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1889 QCOMPARE(o.error(), false);
1890 QCOMPARE(o.invoked(), 8);
1891 QCOMPARE(o.actuals().count(), 1);
1892 QCOMPARE(o.actuals().at(0), QVariant(0));
1895 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1896 QCOMPARE(o.error(), false);
1897 QCOMPARE(o.invoked(), 9);
1898 QCOMPARE(o.actuals().count(), 2);
1899 QCOMPARE(o.actuals().at(0), QVariant(122));
1900 QCOMPARE(o.actuals().at(1), QVariant(9));
1903 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1904 QCOMPARE(o.error(), false);
1905 QCOMPARE(o.invoked(), 10);
1906 QCOMPARE(o.actuals().count(), 1);
1907 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1910 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1911 QCOMPARE(o.error(), false);
1912 QCOMPARE(o.invoked(), 10);
1913 QCOMPARE(o.actuals().count(), 1);
1914 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1917 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1918 QCOMPARE(o.error(), false);
1919 QCOMPARE(o.invoked(), 10);
1920 QCOMPARE(o.actuals().count(), 1);
1921 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1924 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1925 QCOMPARE(o.error(), false);
1926 QCOMPARE(o.invoked(), 10);
1927 QCOMPARE(o.actuals().count(), 1);
1928 QCOMPARE(o.actuals().at(0), QVariant(0));
1931 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1932 QCOMPARE(o.error(), false);
1933 QCOMPARE(o.invoked(), 10);
1934 QCOMPARE(o.actuals().count(), 1);
1935 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1938 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1939 QCOMPARE(o.error(), false);
1940 QCOMPARE(o.invoked(), 10);
1941 QCOMPARE(o.actuals().count(), 1);
1942 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1945 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1946 QCOMPARE(o.error(), false);
1947 QCOMPARE(o.invoked(), 11);
1948 QCOMPARE(o.actuals().count(), 1);
1949 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1952 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1953 QCOMPARE(o.error(), false);
1954 QCOMPARE(o.invoked(), 11);
1955 QCOMPARE(o.actuals().count(), 1);
1956 QCOMPARE(o.actuals().at(0), QVariant("19"));
1960 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1961 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1962 QCOMPARE(o.error(), false);
1963 QCOMPARE(o.invoked(), 11);
1964 QCOMPARE(o.actuals().count(), 1);
1965 QCOMPARE(o.actuals().at(0), QVariant(expected));
1969 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1970 QCOMPARE(o.error(), false);
1971 QCOMPARE(o.invoked(), 11);
1972 QCOMPARE(o.actuals().count(), 1);
1973 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1976 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1977 QCOMPARE(o.error(), false);
1978 QCOMPARE(o.invoked(), 11);
1979 QCOMPARE(o.actuals().count(), 1);
1980 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1983 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1984 QCOMPARE(o.error(), false);
1985 QCOMPARE(o.invoked(), 12);
1986 QCOMPARE(o.actuals().count(), 1);
1987 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1990 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1991 QCOMPARE(o.error(), false);
1992 QCOMPARE(o.invoked(), 12);
1993 QCOMPARE(o.actuals().count(), 1);
1994 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1997 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1998 QCOMPARE(o.error(), false);
1999 QCOMPARE(o.invoked(), 12);
2000 QCOMPARE(o.actuals().count(), 1);
2001 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2004 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2005 QCOMPARE(o.error(), false);
2006 QCOMPARE(o.invoked(), 12);
2007 QCOMPARE(o.actuals().count(), 1);
2008 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2011 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2012 QCOMPARE(o.error(), false);
2013 QCOMPARE(o.invoked(), 12);
2014 QCOMPARE(o.actuals().count(), 1);
2015 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2018 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2019 QCOMPARE(o.error(), false);
2020 QCOMPARE(o.invoked(), 12);
2021 QCOMPARE(o.actuals().count(), 1);
2022 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2025 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2026 QCOMPARE(o.error(), false);
2027 QCOMPARE(o.invoked(), 13);
2028 QCOMPARE(o.actuals().count(), 1);
2029 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2032 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2033 QCOMPARE(o.error(), false);
2034 QCOMPARE(o.invoked(), 13);
2035 QCOMPARE(o.actuals().count(), 1);
2036 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2039 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2040 QCOMPARE(o.error(), false);
2041 QCOMPARE(o.invoked(), 13);
2042 QCOMPARE(o.actuals().count(), 1);
2043 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2046 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2047 QCOMPARE(o.error(), false);
2048 QCOMPARE(o.invoked(), 13);
2049 QCOMPARE(o.actuals().count(), 1);
2050 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2053 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2054 QCOMPARE(o.error(), false);
2055 QCOMPARE(o.invoked(), 13);
2056 QCOMPARE(o.actuals().count(), 1);
2057 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2060 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2061 QCOMPARE(o.error(), false);
2062 QCOMPARE(o.invoked(), 14);
2063 QCOMPARE(o.actuals().count(), 1);
2064 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2067 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2068 QCOMPARE(o.error(), false);
2069 QCOMPARE(o.invoked(), 14);
2070 QCOMPARE(o.actuals().count(), 1);
2071 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2074 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2075 QCOMPARE(o.error(), false);
2076 QCOMPARE(o.invoked(), 14);
2077 QCOMPARE(o.actuals().count(), 1);
2078 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2081 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2082 QCOMPARE(o.error(), false);
2083 QCOMPARE(o.invoked(), 14);
2084 QCOMPARE(o.actuals().count(), 1);
2085 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2088 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2089 QCOMPARE(o.error(), false);
2090 QCOMPARE(o.invoked(), 15);
2091 QCOMPARE(o.actuals().count(), 2);
2092 QCOMPARE(o.actuals().at(0), QVariant(4));
2093 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2096 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2097 QCOMPARE(o.error(), false);
2098 QCOMPARE(o.invoked(), 15);
2099 QCOMPARE(o.actuals().count(), 2);
2100 QCOMPARE(o.actuals().at(0), QVariant(8));
2101 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2104 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2105 QCOMPARE(o.error(), false);
2106 QCOMPARE(o.invoked(), 15);
2107 QCOMPARE(o.actuals().count(), 2);
2108 QCOMPARE(o.actuals().at(0), QVariant(3));
2109 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2112 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2113 QCOMPARE(o.error(), false);
2114 QCOMPARE(o.invoked(), 15);
2115 QCOMPARE(o.actuals().count(), 2);
2116 QCOMPARE(o.actuals().at(0), QVariant(44));
2117 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2120 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2121 QCOMPARE(o.error(), false);
2122 QCOMPARE(o.invoked(), -1);
2123 QCOMPARE(o.actuals().count(), 0);
2126 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2127 QCOMPARE(o.error(), false);
2128 QCOMPARE(o.invoked(), 16);
2129 QCOMPARE(o.actuals().count(), 1);
2130 QCOMPARE(o.actuals().at(0), QVariant(10));
2133 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2134 QCOMPARE(o.error(), false);
2135 QCOMPARE(o.invoked(), 17);
2136 QCOMPARE(o.actuals().count(), 2);
2137 QCOMPARE(o.actuals().at(0), QVariant(10));
2138 QCOMPARE(o.actuals().at(1), QVariant(11));
2141 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2142 QCOMPARE(o.error(), false);
2143 QCOMPARE(o.invoked(), 18);
2144 QCOMPARE(o.actuals().count(), 1);
2145 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2148 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2149 QCOMPARE(o.error(), false);
2150 QCOMPARE(o.invoked(), 19);
2151 QCOMPARE(o.actuals().count(), 1);
2152 QCOMPARE(o.actuals().at(0), QVariant(9));
2155 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2156 QCOMPARE(o.error(), false);
2157 QCOMPARE(o.invoked(), 20);
2158 QCOMPARE(o.actuals().count(), 2);
2159 QCOMPARE(o.actuals().at(0), QVariant(10));
2160 QCOMPARE(o.actuals().at(1), QVariant(19));
2163 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2164 QCOMPARE(o.error(), false);
2165 QCOMPARE(o.invoked(), 20);
2166 QCOMPARE(o.actuals().count(), 2);
2167 QCOMPARE(o.actuals().at(0), QVariant(10));
2168 QCOMPARE(o.actuals().at(1), QVariant(13));
2171 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2172 QCOMPARE(o.error(), false);
2173 QCOMPARE(o.invoked(), -3);
2174 QCOMPARE(o.actuals().count(), 1);
2175 QCOMPARE(o.actuals().at(0), QVariant(9));
2178 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2179 QCOMPARE(o.error(), false);
2180 QCOMPARE(o.invoked(), 21);
2181 QCOMPARE(o.actuals().count(), 2);
2182 QCOMPARE(o.actuals().at(0), QVariant(9));
2183 QCOMPARE(o.actuals().at(1), QVariant());
2186 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2187 QCOMPARE(o.error(), false);
2188 QCOMPARE(o.invoked(), 21);
2189 QCOMPARE(o.actuals().count(), 2);
2190 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2191 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2194 // QTBUG-13047 (check that you can pass registered object types as args)
2195 void tst_qdeclarativeecmascript::invokableObjectArg()
2197 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2199 QObject *o = component.create();
2201 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2203 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2208 // QTBUG-13047 (check that you can return registered object types from methods)
2209 void tst_qdeclarativeecmascript::invokableObjectRet()
2211 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2213 QObject *o = component.create();
2215 QCOMPARE(o->property("test").toBool(), true);
2220 void tst_qdeclarativeecmascript::listToVariant()
2222 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2224 MyQmlContainer container;
2226 QDeclarativeContext context(engine.rootContext());
2227 context.setContextObject(&container);
2229 QObject *object = component.create(&context);
2230 QVERIFY(object != 0);
2232 QVariant v = object->property("test");
2233 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2234 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2240 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2241 void tst_qdeclarativeecmascript::listAssignment()
2243 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2244 QObject *obj = component.create();
2245 QCOMPARE(obj->property("list1length").toInt(), 2);
2246 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2247 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2248 QCOMPARE(list1.count(&list1), list2.count(&list2));
2249 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2250 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2255 void tst_qdeclarativeecmascript::multiEngineObject()
2258 obj.setStringProperty("Howdy planet");
2260 QDeclarativeEngine e1;
2261 e1.rootContext()->setContextProperty("thing", &obj);
2262 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2264 QDeclarativeEngine e2;
2265 e2.rootContext()->setContextProperty("thing", &obj);
2266 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2268 QObject *o1 = c1.create();
2269 QObject *o2 = c2.create();
2271 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2272 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2278 // Test that references to QObjects are cleanup when the object is destroyed
2279 void tst_qdeclarativeecmascript::deletedObject()
2281 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2283 QObject *object = component.create();
2285 QCOMPARE(object->property("test1").toBool(), true);
2286 QCOMPARE(object->property("test2").toBool(), true);
2287 QCOMPARE(object->property("test3").toBool(), true);
2288 QCOMPARE(object->property("test4").toBool(), true);
2293 void tst_qdeclarativeecmascript::attachedPropertyScope()
2295 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2297 QObject *object = component.create();
2298 QVERIFY(object != 0);
2300 MyQmlAttachedObject *attached =
2301 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2302 QVERIFY(attached != 0);
2304 QCOMPARE(object->property("value2").toInt(), 0);
2306 attached->emitMySignal();
2308 QCOMPARE(object->property("value2").toInt(), 9);
2313 void tst_qdeclarativeecmascript::scriptConnect()
2316 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2318 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2319 QVERIFY(object != 0);
2321 QCOMPARE(object->property("test").toBool(), false);
2322 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2323 QCOMPARE(object->property("test").toBool(), true);
2329 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2331 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2332 QVERIFY(object != 0);
2334 QCOMPARE(object->property("test").toBool(), false);
2335 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2336 QCOMPARE(object->property("test").toBool(), true);
2342 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2344 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2345 QVERIFY(object != 0);
2347 QCOMPARE(object->property("test").toBool(), false);
2348 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2349 QCOMPARE(object->property("test").toBool(), true);
2355 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2357 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2358 QVERIFY(object != 0);
2360 QCOMPARE(object->methodCalled(), false);
2361 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2362 QCOMPARE(object->methodCalled(), true);
2368 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2370 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2371 QVERIFY(object != 0);
2373 QCOMPARE(object->methodCalled(), false);
2374 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2375 QCOMPARE(object->methodCalled(), true);
2381 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2383 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2384 QVERIFY(object != 0);
2386 QCOMPARE(object->property("test").toInt(), 0);
2387 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2388 QCOMPARE(object->property("test").toInt(), 2);
2394 void tst_qdeclarativeecmascript::scriptDisconnect()
2397 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2399 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2400 QVERIFY(object != 0);
2402 QCOMPARE(object->property("test").toInt(), 0);
2403 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2404 QCOMPARE(object->property("test").toInt(), 1);
2405 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2406 QCOMPARE(object->property("test").toInt(), 2);
2407 emit object->basicSignal();
2408 QCOMPARE(object->property("test").toInt(), 2);
2409 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2410 QCOMPARE(object->property("test").toInt(), 2);
2416 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2418 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2419 QVERIFY(object != 0);
2421 QCOMPARE(object->property("test").toInt(), 0);
2422 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2423 QCOMPARE(object->property("test").toInt(), 1);
2424 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2425 QCOMPARE(object->property("test").toInt(), 2);
2426 emit object->basicSignal();
2427 QCOMPARE(object->property("test").toInt(), 2);
2428 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2429 QCOMPARE(object->property("test").toInt(), 2);
2435 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2437 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2438 QVERIFY(object != 0);
2440 QCOMPARE(object->property("test").toInt(), 0);
2441 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2442 QCOMPARE(object->property("test").toInt(), 1);
2443 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2444 QCOMPARE(object->property("test").toInt(), 2);
2445 emit object->basicSignal();
2446 QCOMPARE(object->property("test").toInt(), 2);
2447 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2448 QCOMPARE(object->property("test").toInt(), 3);
2453 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2455 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2456 QVERIFY(object != 0);
2458 QCOMPARE(object->property("test").toInt(), 0);
2459 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2460 QCOMPARE(object->property("test").toInt(), 1);
2461 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2462 QCOMPARE(object->property("test").toInt(), 2);
2463 emit object->basicSignal();
2464 QCOMPARE(object->property("test").toInt(), 2);
2465 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2466 QCOMPARE(object->property("test").toInt(), 3);
2472 class OwnershipObject : public QObject
2476 OwnershipObject() { object = new QObject; }
2478 QPointer<QObject> object;
2481 QObject *getObject() { return object; }
2484 void tst_qdeclarativeecmascript::ownership()
2486 OwnershipObject own;
2487 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2488 context->setContextObject(&own);
2491 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2493 QVERIFY(own.object != 0);
2495 QObject *object = component.create(context);
2497 engine.collectGarbage();
2499 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2501 QVERIFY(own.object == 0);
2506 own.object = new QObject(&own);
2509 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2511 QVERIFY(own.object != 0);
2513 QObject *object = component.create(context);
2515 engine.collectGarbage();
2517 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2519 QVERIFY(own.object != 0);
2527 class CppOwnershipReturnValue : public QObject
2531 CppOwnershipReturnValue() : value(0) {}
2532 ~CppOwnershipReturnValue() { delete value; }
2534 Q_INVOKABLE QObject *create() {
2535 value = new QObject;
2536 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2540 Q_INVOKABLE MyQmlObject *createQmlObject() {
2541 MyQmlObject *rv = new MyQmlObject;
2546 QPointer<QObject> value;
2550 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2551 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2553 CppOwnershipReturnValue source;
2556 QDeclarativeEngine engine;
2557 engine.rootContext()->setContextProperty("source", &source);
2559 QVERIFY(source.value == 0);
2561 QDeclarativeComponent component(&engine);
2562 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2564 QObject *object = component.create();
2566 QVERIFY(object != 0);
2567 QVERIFY(source.value != 0);
2572 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2574 QVERIFY(source.value != 0);
2578 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2580 CppOwnershipReturnValue source;
2583 QDeclarativeEngine engine;
2584 engine.rootContext()->setContextProperty("source", &source);
2586 QVERIFY(source.value == 0);
2588 QDeclarativeComponent component(&engine);
2589 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2591 QObject *object = component.create();
2593 QVERIFY(object != 0);
2594 QVERIFY(source.value != 0);
2599 engine.collectGarbage();
2600 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2602 QVERIFY(source.value == 0);
2605 class QListQObjectMethodsObject : public QObject
2609 QListQObjectMethodsObject() {
2610 m_objects.append(new MyQmlObject());
2611 m_objects.append(new MyQmlObject());
2614 ~QListQObjectMethodsObject() {
2615 qDeleteAll(m_objects);
2619 QList<QObject *> getObjects() { return m_objects; }
2622 QList<QObject *> m_objects;
2625 // Tests that returning a QList<QObject*> from a method works
2626 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2628 QListQObjectMethodsObject obj;
2629 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2630 context->setContextObject(&obj);
2632 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2634 QObject *object = component.create(context);
2636 QCOMPARE(object->property("test").toInt(), 2);
2637 QCOMPARE(object->property("test2").toBool(), true);
2644 void tst_qdeclarativeecmascript::strictlyEquals()
2646 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2648 QObject *object = component.create();
2649 QVERIFY(object != 0);
2651 QCOMPARE(object->property("test1").toBool(), true);
2652 QCOMPARE(object->property("test2").toBool(), true);
2653 QCOMPARE(object->property("test3").toBool(), true);
2654 QCOMPARE(object->property("test4").toBool(), true);
2655 QCOMPARE(object->property("test5").toBool(), true);
2656 QCOMPARE(object->property("test6").toBool(), true);
2657 QCOMPARE(object->property("test7").toBool(), true);
2658 QCOMPARE(object->property("test8").toBool(), true);
2663 void tst_qdeclarativeecmascript::compiled()
2665 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2667 QObject *object = component.create();
2668 QVERIFY(object != 0);
2670 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2671 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2672 QCOMPARE(object->property("test3").toBool(), true);
2673 QCOMPARE(object->property("test4").toBool(), false);
2674 QCOMPARE(object->property("test5").toBool(), false);
2675 QCOMPARE(object->property("test6").toBool(), true);
2677 QCOMPARE(object->property("test7").toInt(), 185);
2678 QCOMPARE(object->property("test8").toInt(), 167);
2679 QCOMPARE(object->property("test9").toBool(), true);
2680 QCOMPARE(object->property("test10").toBool(), false);
2681 QCOMPARE(object->property("test11").toBool(), false);
2682 QCOMPARE(object->property("test12").toBool(), true);
2684 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2685 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2686 QCOMPARE(object->property("test15").toBool(), false);
2687 QCOMPARE(object->property("test16").toBool(), true);
2689 QCOMPARE(object->property("test17").toInt(), 5);
2690 QCOMPARE(object->property("test18").toReal(), qreal(176));
2691 QCOMPARE(object->property("test19").toInt(), 7);
2692 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2693 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2694 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2695 QCOMPARE(object->property("test23").toBool(), true);
2696 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2697 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2702 // Test that numbers assigned in bindings as strings work consistently
2703 void tst_qdeclarativeecmascript::numberAssignment()
2705 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2707 QObject *object = component.create();
2708 QVERIFY(object != 0);
2710 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2711 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2712 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2713 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2714 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2716 QCOMPARE(object->property("test5"), QVariant((int)7));
2717 QCOMPARE(object->property("test6"), QVariant((int)7));
2718 QCOMPARE(object->property("test7"), QVariant((int)6));
2719 QCOMPARE(object->property("test8"), QVariant((int)6));
2721 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2722 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2723 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2724 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2729 void tst_qdeclarativeecmascript::propertySplicing()
2731 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2733 QObject *object = component.create();
2734 QVERIFY(object != 0);
2736 QCOMPARE(object->property("test").toBool(), true);
2742 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2744 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2746 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2747 QVERIFY(object != 0);
2749 MyQmlObject::MyType type;
2750 type.value = 0x8971123;
2751 emit object->signalWithUnknownType(type);
2753 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2755 QCOMPARE(result.value, type.value);
2761 void tst_qdeclarativeecmascript::moduleApi_data()
2763 QTest::addColumn<QUrl>("testfile");
2764 QTest::addColumn<QString>("errorMessage");
2765 QTest::addColumn<QStringList>("warningMessages");
2766 QTest::addColumn<QStringList>("readProperties");
2767 QTest::addColumn<QVariantList>("readExpectedValues");
2768 QTest::addColumn<QStringList>("writeProperties");
2769 QTest::addColumn<QVariantList>("writeValues");
2770 QTest::addColumn<QStringList>("readBackProperties");
2771 QTest::addColumn<QVariantList>("readBackExpectedValues");
2773 QTest::newRow("qobject, register + read + method")
2774 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2777 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2778 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2779 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2785 QTest::newRow("script, register + read")
2786 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2789 << (QStringList() << "scriptTest")
2790 << (QVariantList() << 13)
2796 QTest::newRow("qobject, caching + read")
2797 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2800 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2801 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2807 QTest::newRow("script, caching + read")
2808 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2811 << (QStringList() << "scriptTest")
2812 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2818 QTest::newRow("qobject, writing + readonly constraints")
2819 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2821 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2822 << (QStringList() << "readOnlyProperty" << "writableProperty")
2823 << (QVariantList() << 20 << 50)
2824 << (QStringList() << "firstProperty" << "writableProperty")
2825 << (QVariantList() << 30 << 30)
2826 << (QStringList() << "readOnlyProperty" << "writableProperty")
2827 << (QVariantList() << 20 << 30);
2829 QTest::newRow("script, writing + readonly constraints")
2830 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2832 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2833 << (QStringList() << "readBack" << "unchanged")
2834 << (QVariantList() << 13 << 42)
2835 << (QStringList() << "firstProperty" << "secondProperty")
2836 << (QVariantList() << 30 << 30)
2837 << (QStringList() << "readBack" << "unchanged")
2838 << (QVariantList() << 30 << 42);
2840 QTest::newRow("qobject module API enum values in JS")
2841 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2844 << (QStringList() << "enumValue" << "enumMethod")
2845 << (QVariantList() << 42 << 30)
2851 QTest::newRow("qobject, invalid major version fail")
2852 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2853 << QString("QDeclarativeComponent: Component is not ready")
2862 QTest::newRow("qobject, invalid minor version fail")
2863 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2864 << QString("QDeclarativeComponent: Component is not ready")
2874 void tst_qdeclarativeecmascript::moduleApi()
2876 QFETCH(QUrl, testfile);
2877 QFETCH(QString, errorMessage);
2878 QFETCH(QStringList, warningMessages);
2879 QFETCH(QStringList, readProperties);
2880 QFETCH(QVariantList, readExpectedValues);
2881 QFETCH(QStringList, writeProperties);
2882 QFETCH(QVariantList, writeValues);
2883 QFETCH(QStringList, readBackProperties);
2884 QFETCH(QVariantList, readBackExpectedValues);
2886 QDeclarativeComponent component(&engine, testfile);
2888 if (!errorMessage.isEmpty())
2889 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
2891 if (warningMessages.size())
2892 foreach (const QString &warning, warningMessages)
2893 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
2895 QObject *object = component.create();
2896 if (!errorMessage.isEmpty()) {
2897 QVERIFY(object == 0);
2899 QVERIFY(object != 0);
2900 for (int i = 0; i < readProperties.size(); ++i)
2901 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
2902 for (int i = 0; i < writeProperties.size(); ++i)
2903 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
2904 for (int i = 0; i < readBackProperties.size(); ++i)
2905 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
2910 void tst_qdeclarativeecmascript::importScripts()
2912 QObject *object = 0;
2914 // first, ensure that the required behaviour works.
2915 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2916 object = component.create();
2917 QVERIFY(object != 0);
2918 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2919 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2920 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2921 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2924 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2925 object = componentTwo.create();
2926 QVERIFY(object != 0);
2927 QCOMPARE(object->property("componentError"), QVariant(5));
2930 // then, ensure that unintended behaviour does not work.
2931 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2932 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2933 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2934 object = failOneComponent.create();
2935 QVERIFY(object != 0);
2936 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2938 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2939 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2940 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2941 object = failTwoComponent.create();
2942 QVERIFY(object != 0);
2943 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2945 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2946 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2947 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2948 object = failThreeComponent.create();
2949 QVERIFY(object != 0);
2950 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2952 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2953 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2954 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2955 object = failFourComponent.create();
2956 QVERIFY(object != 0);
2957 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2959 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2960 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2961 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2962 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2963 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2964 object = failFiveComponent.create();
2965 QVERIFY(object != 0);
2966 QCOMPARE(object->property("componentError"), QVariant(0));
2969 // also, test that importing scripts with .pragma library works as required
2970 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2971 object = pragmaLibraryComponent.create();
2972 QVERIFY(object != 0);
2973 QCOMPARE(object->property("testValue"), QVariant(31));
2976 // and that .pragma library scripts don't inherit imports from any .qml file
2977 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2978 object = pragmaLibraryComponentTwo.create();
2979 QVERIFY(object != 0);
2980 QCOMPARE(object->property("testValue"), QVariant(0));
2984 void tst_qdeclarativeecmascript::scarceResources()
2986 QPixmap origPixmap(100, 100);
2987 origPixmap.fill(Qt::blue);
2989 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2990 ScarceResourceObject *eo = 0;
2991 QObject *object = 0;
2993 // in the following three cases, the instance created from the component
2994 // has a property which is a copy of the scarce resource; hence, the
2995 // resource should NOT be detached prior to deletion of the object instance,
2996 // unless the resource is destroyed explicitly.
2997 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2998 object = component.create();
2999 QVERIFY(object != 0);
3000 QVERIFY(object->property("scarceResourceCopy").isValid());
3001 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3002 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3003 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3004 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3007 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3008 object = componentTwo.create();
3009 QVERIFY(object != 0);
3010 QVERIFY(object->property("scarceResourceCopy").isValid());
3011 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3012 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3013 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3014 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3017 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3018 object = componentThree.create();
3019 QVERIFY(object != 0);
3020 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3021 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3022 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3023 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3026 // in the following three cases, no other copy should exist in memory,
3027 // and so it should be detached (unless explicitly preserved).
3028 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3029 object = componentFour.create();
3030 QVERIFY(object != 0);
3031 QVERIFY(object->property("scarceResourceTest").isValid());
3032 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3033 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3034 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3035 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3038 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3039 object = componentFive.create();
3040 QVERIFY(object != 0);
3041 QVERIFY(object->property("scarceResourceTest").isValid());
3042 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3043 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3044 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3045 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3048 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3049 object = componentSix.create();
3050 QVERIFY(object != 0);
3051 QVERIFY(object->property("scarceResourceTest").isValid());
3052 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3053 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3054 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3055 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3058 // test that scarce resources are handled correctly for imports
3059 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3060 object = componentSeven.create();
3061 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3062 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3065 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3066 object = componentEight.create();
3067 QVERIFY(object != 0);
3068 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3069 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3072 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3073 object = componentNine.create();
3074 QVERIFY(object != 0);
3075 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3076 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3077 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3078 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3079 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3080 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3083 // test that scarce resources are handled properly in signal invocation
3084 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3085 object = componentTen.create();
3086 QVERIFY(object != 0);
3087 QObject *srsc = object->findChild<QObject*>("srsc");
3089 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3090 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3091 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3092 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3093 QMetaObject::invokeMethod(srsc, "testSignal");
3094 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3095 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3096 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3097 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3098 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3099 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3100 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3101 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3102 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3103 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3106 // test that scarce resources are handled properly from js functions in qml files
3107 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3108 object = componentEleven.create();
3109 QVERIFY(object != 0);
3110 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3111 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3112 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3113 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3114 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3115 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3116 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3117 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3118 QMetaObject::invokeMethod(object, "releaseScarceResource");
3119 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3120 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3121 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3122 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3125 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3126 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3127 object = componentTwelve.create();
3128 QVERIFY(object != 0);
3129 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3130 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3131 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3132 QString srp_name = object->property("srp_name").toString();
3133 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3134 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3135 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3136 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3137 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3138 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3139 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3143 void tst_qdeclarativeecmascript::propertyChangeSlots()
3145 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3146 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3147 QObject *object = component.create();
3148 QVERIFY(object != 0);
3151 // ensure that invalid property names fail properly.
3152 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3153 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3154 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3155 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3156 object = e1.create();
3157 QVERIFY(object == 0);
3160 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3161 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3162 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3163 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3164 object = e2.create();
3165 QVERIFY(object == 0);
3168 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3169 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3170 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3171 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3172 object = e3.create();
3173 QVERIFY(object == 0);
3176 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3177 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3178 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3179 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3180 object = e4.create();
3181 QVERIFY(object == 0);
3185 // Ensure that QObject type conversion works on binding assignment
3186 void tst_qdeclarativeecmascript::elementAssign()
3188 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3190 QObject *object = component.create();
3191 QVERIFY(object != 0);
3193 QCOMPARE(object->property("test").toBool(), true);
3199 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3201 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3203 QObject *object = component.create();
3204 QVERIFY(object != 0);
3206 QCOMPARE(object->property("test").toBool(), true);
3212 void tst_qdeclarativeecmascript::booleanConversion()
3214 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3216 QObject *object = component.create();
3217 QVERIFY(object != 0);
3219 QCOMPARE(object->property("test_true1").toBool(), true);
3220 QCOMPARE(object->property("test_true2").toBool(), true);
3221 QCOMPARE(object->property("test_true3").toBool(), true);
3222 QCOMPARE(object->property("test_true4").toBool(), true);
3223 QCOMPARE(object->property("test_true5").toBool(), true);
3225 QCOMPARE(object->property("test_false1").toBool(), false);
3226 QCOMPARE(object->property("test_false2").toBool(), false);
3227 QCOMPARE(object->property("test_false3").toBool(), false);
3232 void tst_qdeclarativeecmascript::handleReferenceManagement()
3237 // Linear QObject reference
3238 QDeclarativeEngine hrmEngine;
3239 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3240 QObject *object = component.create();
3241 QVERIFY(object != 0);
3242 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3243 cro->setDtorCount(&dtorCount);
3244 QMetaObject::invokeMethod(object, "createReference");
3245 QMetaObject::invokeMethod(object, "performGc");
3246 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3247 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3249 hrmEngine.collectGarbage();
3250 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3251 QCOMPARE(dtorCount, 3);
3256 // Circular QObject reference
3257 QDeclarativeEngine hrmEngine;
3258 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3259 QObject *object = component.create();
3260 QVERIFY(object != 0);
3261 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3262 cro->setDtorCount(&dtorCount);
3263 QMetaObject::invokeMethod(object, "circularReference");
3264 QMetaObject::invokeMethod(object, "performGc");
3265 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3266 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3268 hrmEngine.collectGarbage();
3269 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3270 QCOMPARE(dtorCount, 3);
3275 // Linear handle reference
3276 QDeclarativeEngine hrmEngine;
3277 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3278 QObject *object = component.create();
3279 QVERIFY(object != 0);
3280 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3282 crh->setDtorCount(&dtorCount);
3283 QMetaObject::invokeMethod(object, "createReference");
3284 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3285 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3286 QVERIFY(first != 0);
3287 QVERIFY(second != 0);
3288 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3289 // now we have to reparent second and make second owned by JS.
3290 second->setParent(0);
3291 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3292 QMetaObject::invokeMethod(object, "performGc");
3293 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3294 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3296 hrmEngine.collectGarbage();
3297 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3298 QCOMPARE(dtorCount, 3);
3303 // Circular handle reference
3304 QDeclarativeEngine hrmEngine;
3305 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3306 QObject *object = component.create();
3307 QVERIFY(object != 0);
3308 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3310 crh->setDtorCount(&dtorCount);
3311 QMetaObject::invokeMethod(object, "circularReference");
3312 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3313 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3314 QVERIFY(first != 0);
3315 QVERIFY(second != 0);
3316 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3317 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3318 // now we have to reparent and change ownership.
3319 first->setParent(0);
3320 second->setParent(0);
3321 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3322 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3323 QMetaObject::invokeMethod(object, "performGc");
3324 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3325 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3327 hrmEngine.collectGarbage();
3328 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3329 QCOMPARE(dtorCount, 3);
3334 // multiple engine interaction - linear reference
3335 QDeclarativeEngine hrmEngine1;
3336 QDeclarativeEngine hrmEngine2;
3337 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3338 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3339 QObject *object1 = component1.create();
3340 QObject *object2 = component2.create();
3341 QVERIFY(object1 != 0);
3342 QVERIFY(object2 != 0);
3343 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3344 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3347 crh1->setDtorCount(&dtorCount);
3348 crh2->setDtorCount(&dtorCount);
3349 QMetaObject::invokeMethod(object1, "createReference");
3350 QMetaObject::invokeMethod(object2, "createReference");
3351 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3352 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3353 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3354 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3355 QVERIFY(first1 != 0);
3356 QVERIFY(second1 != 0);
3357 QVERIFY(first2 != 0);
3358 QVERIFY(second2 != 0);
3359 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3360 // now we have to reparent second2 and make second2 owned by JS.
3361 second2->setParent(0);
3362 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3363 QMetaObject::invokeMethod(object1, "performGc");
3364 QMetaObject::invokeMethod(object2, "performGc");
3365 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3366 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3369 hrmEngine1.collectGarbage();
3370 hrmEngine2.collectGarbage();
3371 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3372 QCOMPARE(dtorCount, 6);
3377 // multiple engine interaction - circular reference
3378 QDeclarativeEngine hrmEngine1;
3379 QDeclarativeEngine hrmEngine2;
3380 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3381 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3382 QObject *object1 = component1.create();
3383 QObject *object2 = component2.create();
3384 QVERIFY(object1 != 0);
3385 QVERIFY(object2 != 0);
3386 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3387 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3390 crh1->setDtorCount(&dtorCount);
3391 crh2->setDtorCount(&dtorCount);
3392 QMetaObject::invokeMethod(object1, "createReference");
3393 QMetaObject::invokeMethod(object2, "createReference");
3394 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3395 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3396 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3397 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3398 QVERIFY(first1 != 0);
3399 QVERIFY(second1 != 0);
3400 QVERIFY(first2 != 0);
3401 QVERIFY(second2 != 0);
3402 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3403 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3404 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3405 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3406 // now we have to reparent and change ownership to JS.
3407 first1->setParent(0);
3408 second1->setParent(0);
3409 first2->setParent(0);
3410 second2->setParent(0);
3411 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3412 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3413 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3414 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3415 QMetaObject::invokeMethod(object1, "performGc");
3416 QMetaObject::invokeMethod(object2, "performGc");
3417 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3418 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3421 hrmEngine1.collectGarbage();
3422 hrmEngine2.collectGarbage();
3423 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3424 QCOMPARE(dtorCount, 6);
3429 // multiple engine interaction - linear reference with engine deletion
3430 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3431 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3432 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3433 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3434 QObject *object1 = component1.create();
3435 QObject *object2 = component2.create();
3436 QVERIFY(object1 != 0);
3437 QVERIFY(object2 != 0);
3438 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3439 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3442 crh1->setDtorCount(&dtorCount);
3443 crh2->setDtorCount(&dtorCount);
3444 QMetaObject::invokeMethod(object1, "createReference");
3445 QMetaObject::invokeMethod(object2, "createReference");
3446 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3447 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3448 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3449 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3450 QVERIFY(first1 != 0);
3451 QVERIFY(second1 != 0);
3452 QVERIFY(first2 != 0);
3453 QVERIFY(second2 != 0);
3454 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3455 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3456 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3457 // now we have to reparent and change ownership to JS.
3458 first1->setParent(crh1);
3459 second1->setParent(0);
3460 first2->setParent(0);
3461 second2->setParent(0);
3462 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3463 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3464 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3465 QMetaObject::invokeMethod(object1, "performGc");
3466 QMetaObject::invokeMethod(object2, "performGc");
3467 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3468 QCOMPARE(dtorCount, 0);
3470 QMetaObject::invokeMethod(object1, "performGc");
3471 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3472 QCOMPARE(dtorCount, 0);
3475 hrmEngine1->collectGarbage();
3476 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3477 QCOMPARE(dtorCount, 6);
3482 // Test that assigning a null object works
3483 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
3484 void tst_qdeclarativeecmascript::nullObjectBinding()
3486 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
3488 QObject *object = component.create();
3489 QVERIFY(object != 0);
3491 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
3496 // Test that bindings don't evaluate once the engine has been destroyed
3497 void tst_qdeclarativeecmascript::deletedEngine()
3499 QDeclarativeEngine *engine = new QDeclarativeEngine;
3500 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
3502 QObject *object = component.create();
3503 QVERIFY(object != 0);
3505 QCOMPARE(object->property("a").toInt(), 39);
3506 object->setProperty("b", QVariant(9));
3507 QCOMPARE(object->property("a").toInt(), 117);
3511 QCOMPARE(object->property("a").toInt(), 117);
3512 object->setProperty("b", QVariant(10));
3513 QCOMPARE(object->property("a").toInt(), 117);
3518 // Test the crashing part of QTBUG-9705
3519 void tst_qdeclarativeecmascript::libraryScriptAssert()
3521 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3523 QObject *object = component.create();
3524 QVERIFY(object != 0);
3529 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3531 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3533 QObject *object = component.create();
3534 QVERIFY(object != 0);
3536 QCOMPARE(object->property("test1").toInt(), 10);
3537 QCOMPARE(object->property("test2").toInt(), 11);
3539 object->setProperty("runTest", true);
3541 QCOMPARE(object->property("test1"), QVariant());
3542 QCOMPARE(object->property("test2"), QVariant());
3548 void tst_qdeclarativeecmascript::qtbug_9792()
3550 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3552 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3554 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3555 QVERIFY(object != 0);
3557 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3558 object->basicSignal();
3562 transientErrorsMsgCount = 0;
3563 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3565 object->basicSignal();
3567 qInstallMsgHandler(old);
3569 QCOMPARE(transientErrorsMsgCount, 0);
3574 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3575 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3577 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3579 QObject *o = component.create();
3582 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3583 QVERIFY(nested != 0);
3585 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3588 nested = qvariant_cast<QObject *>(o->property("object"));
3589 QVERIFY(nested == 0);
3591 // If the bug is present, the next line will crash
3595 // Test that we shut down without stupid warnings
3596 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3599 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3601 QObject *o = component.create();
3603 transientErrorsMsgCount = 0;
3604 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3608 qInstallMsgHandler(old);
3610 QCOMPARE(transientErrorsMsgCount, 0);
3615 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3617 QObject *o = component.create();
3619 transientErrorsMsgCount = 0;
3620 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3624 qInstallMsgHandler(old);
3626 QCOMPARE(transientErrorsMsgCount, 0);
3630 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3633 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3635 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3638 QVERIFY(o->objectProperty() != 0);
3640 o->setProperty("runTest", true);
3642 QVERIFY(o->objectProperty() == 0);
3648 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3650 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3653 QVERIFY(o->objectProperty() == 0);
3659 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3661 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3663 QString url = component.url().toString();
3664 QString warning = url + ":4: Unable to assign a function to a property.";
3665 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3667 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3670 QVERIFY(!o->property("a").isValid());
3675 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3677 QFETCH(QString, triggerProperty);
3679 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3680 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3682 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3684 QVERIFY(!o->property("a").isValid());
3686 o->setProperty("aNumber", QVariant(5));
3687 o->setProperty(triggerProperty.toUtf8().constData(), true);
3688 QCOMPARE(o->property("a"), QVariant(50));
3690 o->setProperty("aNumber", QVariant(10));
3691 QCOMPARE(o->property("a"), QVariant(100));
3696 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3698 QTest::addColumn<QString>("triggerProperty");
3700 QTest::newRow("assign to property") << "assignToProperty";
3701 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3703 QTest::newRow("assign to value type") << "assignToValueType";
3705 QTest::newRow("use 'this'") << "assignWithThis";
3706 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3709 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3711 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3712 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3714 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3716 QVERIFY(!o->property("a").isValid());
3718 o->setProperty("assignFuncWithoutReturn", true);
3719 QVERIFY(!o->property("a").isValid());
3721 QString url = component.url().toString();
3722 QString warning = url + ":67: Unable to assign QString to int";
3723 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3724 o->setProperty("assignWrongType", true);
3726 warning = url + ":71: Unable to assign QString to int";
3727 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3728 o->setProperty("assignWrongTypeToValueType", true);
3733 void tst_qdeclarativeecmascript::eval()
3735 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3737 QObject *o = component.create();
3740 QCOMPARE(o->property("test1").toBool(), true);
3741 QCOMPARE(o->property("test2").toBool(), true);
3742 QCOMPARE(o->property("test3").toBool(), true);
3743 QCOMPARE(o->property("test4").toBool(), true);
3744 QCOMPARE(o->property("test5").toBool(), true);
3749 void tst_qdeclarativeecmascript::function()
3751 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3753 QObject *o = component.create();
3756 QCOMPARE(o->property("test1").toBool(), true);
3757 QCOMPARE(o->property("test2").toBool(), true);
3758 QCOMPARE(o->property("test3").toBool(), true);
3763 // Test the "Qt.include" method
3764 void tst_qdeclarativeecmascript::include()
3766 // Non-library relative include
3768 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3769 QObject *o = component.create();
3772 QCOMPARE(o->property("test0").toInt(), 99);
3773 QCOMPARE(o->property("test1").toBool(), true);
3774 QCOMPARE(o->property("test2").toBool(), true);
3775 QCOMPARE(o->property("test2_1").toBool(), true);
3776 QCOMPARE(o->property("test3").toBool(), true);
3777 QCOMPARE(o->property("test3_1").toBool(), true);
3782 // Library relative include
3784 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3785 QObject *o = component.create();
3788 QCOMPARE(o->property("test0").toInt(), 99);
3789 QCOMPARE(o->property("test1").toBool(), true);
3790 QCOMPARE(o->property("test2").toBool(), true);
3791 QCOMPARE(o->property("test2_1").toBool(), true);
3792 QCOMPARE(o->property("test3").toBool(), true);
3793 QCOMPARE(o->property("test3_1").toBool(), true);
3800 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3801 QObject *o = component.create();
3804 QCOMPARE(o->property("test1").toBool(), true);
3805 QCOMPARE(o->property("test2").toBool(), true);
3806 QCOMPARE(o->property("test3").toBool(), true);
3807 QCOMPARE(o->property("test4").toBool(), true);
3808 QCOMPARE(o->property("test5").toBool(), true);
3809 QCOMPARE(o->property("test6").toBool(), true);
3814 // Including file with ".pragma library"
3816 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3817 QObject *o = component.create();
3819 QCOMPARE(o->property("test1").toInt(), 100);
3826 TestHTTPServer server(8111);
3827 QVERIFY(server.isValid());
3828 server.serveDirectory(SRCDIR "/data");
3830 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3831 QObject *o = component.create();
3834 QTRY_VERIFY(o->property("done").toBool() == true);
3835 QTRY_VERIFY(o->property("done2").toBool() == true);
3837 QCOMPARE(o->property("test1").toBool(), true);
3838 QCOMPARE(o->property("test2").toBool(), true);
3839 QCOMPARE(o->property("test3").toBool(), true);
3840 QCOMPARE(o->property("test4").toBool(), true);
3841 QCOMPARE(o->property("test5").toBool(), true);
3843 QCOMPARE(o->property("test6").toBool(), true);
3844 QCOMPARE(o->property("test7").toBool(), true);
3845 QCOMPARE(o->property("test8").toBool(), true);
3846 QCOMPARE(o->property("test9").toBool(), true);
3847 QCOMPARE(o->property("test10").toBool(), true);
3854 TestHTTPServer server(8111);
3855 QVERIFY(server.isValid());
3856 server.serveDirectory(SRCDIR "/data");
3858 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3859 QObject *o = component.create();
3862 QTRY_VERIFY(o->property("done").toBool() == true);
3864 QCOMPARE(o->property("test1").toBool(), true);
3865 QCOMPARE(o->property("test2").toBool(), true);
3866 QCOMPARE(o->property("test3").toBool(), true);
3872 void tst_qdeclarativeecmascript::signalHandlers()
3874 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
3875 QObject *o = component.create();
3878 QVERIFY(o->property("count").toInt() == 0);
3879 QMetaObject::invokeMethod(o, "testSignalCall");
3880 QCOMPARE(o->property("count").toInt(), 1);
3882 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
3883 QCOMPARE(o->property("count").toInt(), 1);
3884 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
3886 QVERIFY(o->property("funcCount").toInt() == 0);
3887 QMetaObject::invokeMethod(o, "testSignalConnection");
3888 QCOMPARE(o->property("funcCount").toInt(), 1);
3890 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
3891 QCOMPARE(o->property("funcCount").toInt(), 2);
3893 QMetaObject::invokeMethod(o, "testSignalDefined");
3894 QCOMPARE(o->property("definedResult").toBool(), true);
3896 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
3897 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
3902 void tst_qdeclarativeecmascript::qtbug_10696()
3904 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3905 QObject *o = component.create();
3910 void tst_qdeclarativeecmascript::qtbug_11606()
3912 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3913 QObject *o = component.create();
3915 QCOMPARE(o->property("test").toBool(), true);
3919 void tst_qdeclarativeecmascript::qtbug_11600()
3921 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3922 QObject *o = component.create();
3924 QCOMPARE(o->property("test").toBool(), true);
3928 // Reading and writing non-scriptable properties should fail
3929 void tst_qdeclarativeecmascript::nonscriptable()
3931 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3932 QObject *o = component.create();
3934 QCOMPARE(o->property("readOk").toBool(), true);
3935 QCOMPARE(o->property("writeOk").toBool(), true);
3939 // deleteLater() should not be callable from QML
3940 void tst_qdeclarativeecmascript::deleteLater()
3942 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3943 QObject *o = component.create();
3945 QCOMPARE(o->property("test").toBool(), true);
3949 void tst_qdeclarativeecmascript::in()
3951 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3952 QObject *o = component.create();
3954 QCOMPARE(o->property("test1").toBool(), true);
3955 QCOMPARE(o->property("test2").toBool(), true);
3959 void tst_qdeclarativeecmascript::sharedAttachedObject()
3961 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3962 QObject *o = component.create();
3964 QCOMPARE(o->property("test1").toBool(), true);
3965 QCOMPARE(o->property("test2").toBool(), true);
3970 void tst_qdeclarativeecmascript::objectName()
3972 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3973 QObject *o = component.create();
3976 QCOMPARE(o->property("test1").toString(), QString("hello"));
3977 QCOMPARE(o->property("test2").toString(), QString("ell"));
3979 o->setObjectName("world");
3981 QCOMPARE(o->property("test1").toString(), QString("world"));
3982 QCOMPARE(o->property("test2").toString(), QString("orl"));
3987 void tst_qdeclarativeecmascript::writeRemovesBinding()
3989 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3990 QObject *o = component.create();
3993 QCOMPARE(o->property("test").toBool(), true);
3998 // Test bindings assigned to alias properties actually assign to the alias' target
3999 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4001 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4002 QObject *o = component.create();
4005 QCOMPARE(o->property("test").toBool(), true);
4010 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4011 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4014 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4015 QObject *o = component.create();
4018 QCOMPARE(o->property("test").toBool(), true);
4024 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4025 QObject *o = component.create();
4028 QCOMPARE(o->property("test").toBool(), true);
4034 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4035 QObject *o = component.create();
4038 QCOMPARE(o->property("test").toBool(), true);
4044 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4045 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4048 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4049 QObject *o = component.create();
4052 QCOMPARE(o->property("test").toBool(), true);
4058 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4059 QObject *o = component.create();
4062 QCOMPARE(o->property("test").toBool(), true);
4068 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4069 QObject *o = component.create();
4072 QCOMPARE(o->property("test").toBool(), true);
4078 // Allow an alais to a composite element
4080 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4082 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4084 QObject *object = component.create();
4085 QVERIFY(object != 0);
4090 void tst_qdeclarativeecmascript::revisionErrors()
4093 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4094 QString url = component.url().toString();
4096 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4097 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4098 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4100 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4101 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4102 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4103 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4104 QVERIFY(object != 0);
4108 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4109 QString url = component.url().toString();
4111 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4112 // method2, prop2 from MyRevisionedClass not available
4113 // method4, prop4 from MyRevisionedSubclass not available
4114 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4115 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4116 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4117 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4118 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4120 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4121 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4122 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4123 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4124 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4125 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4126 QVERIFY(object != 0);
4130 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4131 QString url = component.url().toString();
4133 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4134 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4135 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4136 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4137 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4138 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4139 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4140 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4141 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4142 QVERIFY(object != 0);
4147 void tst_qdeclarativeecmascript::revision()
4150 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4151 QString url = component.url().toString();
4153 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4154 QVERIFY(object != 0);
4158 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4159 QString url = component.url().toString();
4161 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4162 QVERIFY(object != 0);
4166 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4167 QString url = component.url().toString();
4169 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4170 QVERIFY(object != 0);
4173 // Test that non-root classes can resolve revisioned methods
4175 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4177 QObject *object = component.create();
4178 QVERIFY(object != 0);
4179 QCOMPARE(object->property("test").toReal(), 11.);
4184 void tst_qdeclarativeecmascript::realToInt()
4186 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
4187 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
4188 QVERIFY(object != 0);
4190 QMetaObject::invokeMethod(object, "test1");
4191 QCOMPARE(object->value(), int(4));
4192 QMetaObject::invokeMethod(object, "test2");
4193 QCOMPARE(object->value(), int(8));
4195 void tst_qdeclarativeecmascript::dynamicString()
4197 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
4198 QObject *object = component.create();
4199 QVERIFY(object != 0);
4200 QCOMPARE(object->property("stringProperty").toString(),
4201 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
4204 void tst_qdeclarativeecmascript::automaticSemicolon()
4206 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
4207 QObject *object = component.create();
4208 QVERIFY(object != 0);
4211 QTEST_MAIN(tst_qdeclarativeecmascript)
4213 #include "tst_qdeclarativeecmascript.moc"